blob: ed0efbe8440596948d2cba771abadb81d164d800 [file] [log] [blame]
sewardjb4112022007-11-09 22:49:28 +00001
2/*--------------------------------------------------------------------*/
3/*--- Helgrind: a Valgrind tool for detecting errors ---*/
4/*--- in threaded programs. hg_main.c ---*/
5/*--------------------------------------------------------------------*/
6
7/*
8 This file is part of Helgrind, a Valgrind tool for detecting errors
9 in threaded programs.
10
sewardj0f157dd2013-10-18 14:27:36 +000011 Copyright (C) 2007-2013 OpenWorks LLP
sewardjb4112022007-11-09 22:49:28 +000012 info@open-works.co.uk
13
sewardj0f157dd2013-10-18 14:27:36 +000014 Copyright (C) 2007-2013 Apple, Inc.
njnf76d27a2009-05-28 01:53:07 +000015
sewardjb4112022007-11-09 22:49:28 +000016 This program is free software; you can redistribute it and/or
17 modify it under the terms of the GNU General Public License as
18 published by the Free Software Foundation; either version 2 of the
19 License, or (at your option) any later version.
20
21 This program is distributed in the hope that it will be useful, but
22 WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 General Public License for more details.
25
26 You should have received a copy of the GNU General Public License
27 along with this program; if not, write to the Free Software
28 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
29 02111-1307, USA.
30
31 The GNU General Public License is contained in the file COPYING.
32
33 Neither the names of the U.S. Department of Energy nor the
34 University of California nor the names of its contributors may be
35 used to endorse or promote products derived from this software
36 without prior written permission.
37*/
38
39#include "pub_tool_basics.h"
philippef5774342014-05-03 11:12:50 +000040#include "pub_tool_gdbserver.h"
sewardjb4112022007-11-09 22:49:28 +000041#include "pub_tool_libcassert.h"
42#include "pub_tool_libcbase.h"
43#include "pub_tool_libcprint.h"
sewardjb4112022007-11-09 22:49:28 +000044#include "pub_tool_threadstate.h"
45#include "pub_tool_tooliface.h"
46#include "pub_tool_hashtable.h"
47#include "pub_tool_replacemalloc.h"
48#include "pub_tool_machine.h"
49#include "pub_tool_options.h"
50#include "pub_tool_xarray.h"
51#include "pub_tool_stacktrace.h"
sewardj896f6f92008-08-19 08:38:52 +000052#include "pub_tool_wordfm.h"
sewardja0eee322009-07-31 08:46:35 +000053#include "pub_tool_debuginfo.h" // VG_(find_seginfo), VG_(seginfo_soname)
54#include "pub_tool_redir.h" // sonames for the dynamic linkers
55#include "pub_tool_vki.h" // VKI_PAGE_SIZE
sewardj61bc2c52011-02-09 10:34:00 +000056#include "pub_tool_libcproc.h" // VG_(atfork)
sewardj234e5582011-02-09 12:47:23 +000057#include "pub_tool_aspacemgr.h" // VG_(am_is_valid_for_client)
philippe5fbc9762013-12-01 19:28:48 +000058#include "pub_tool_poolalloc.h"
philippe07c08522014-05-14 20:39:27 +000059#include "pub_tool_addrinfo.h"
sewardjb4112022007-11-09 22:49:28 +000060
sewardjf98e1c02008-10-25 16:22:41 +000061#include "hg_basics.h"
62#include "hg_wordset.h"
philippef5774342014-05-03 11:12:50 +000063#include "hg_addrdescr.h"
sewardjf98e1c02008-10-25 16:22:41 +000064#include "hg_lock_n_thread.h"
65#include "hg_errors.h"
66
67#include "libhb.h"
68
sewardjb4112022007-11-09 22:49:28 +000069#include "helgrind.h"
70
sewardjf98e1c02008-10-25 16:22:41 +000071
72// FIXME: new_mem_w_tid ignores the supplied tid. (wtf?!)
73
74// FIXME: when client destroys a lock or a CV, remove these
75// from our mappings, so that the associated SO can be freed up
sewardjb4112022007-11-09 22:49:28 +000076
77/*----------------------------------------------------------------*/
78/*--- ---*/
79/*----------------------------------------------------------------*/
80
sewardj11e352f2007-11-30 11:11:02 +000081/* Note this needs to be compiled with -fno-strict-aliasing, since it
82 contains a whole bunch of calls to lookupFM etc which cast between
83 Word and pointer types. gcc rightly complains this breaks ANSI C
84 strict aliasing rules, at -O2. No complaints at -O, but -O2 gives
85 worthwhile performance benefits over -O.
sewardjc17be792007-11-10 22:50:13 +000086*/
sewardjb4112022007-11-09 22:49:28 +000087
88// FIXME what is supposed to happen to locks in memory which
89// is relocated as a result of client realloc?
90
sewardjb4112022007-11-09 22:49:28 +000091// FIXME put referencing ThreadId into Thread and get
92// rid of the slow reverse mapping function.
93
94// FIXME accesses to NoAccess areas: change state to Excl?
95
96// FIXME report errors for accesses of NoAccess memory?
97
98// FIXME pth_cond_wait/timedwait wrappers. Even if these fail,
99// the thread still holds the lock.
100
101/* ------------ Debug/trace options ------------ */
102
sewardjb4112022007-11-09 22:49:28 +0000103// 0 for silent, 1 for some stuff, 2 for lots of stuff
104#define SHOW_EVENTS 0
105
sewardjb4112022007-11-09 22:49:28 +0000106
florian6bf37262012-10-21 03:23:36 +0000107static void all__sanity_check ( const HChar* who ); /* fwds */
sewardjb4112022007-11-09 22:49:28 +0000108
philipped99c26a2012-07-31 22:17:28 +0000109#define HG_CLI__DEFAULT_MALLOC_REDZONE_SZB 16 /* let's say */
sewardjb4112022007-11-09 22:49:28 +0000110
111// 0 for none, 1 for dump at end of run
112#define SHOW_DATA_STRUCTURES 0
113
114
sewardjb4112022007-11-09 22:49:28 +0000115/* ------------ Misc comments ------------ */
116
117// FIXME: don't hardwire initial entries for root thread.
118// Instead, let the pre_thread_ll_create handler do this.
119
sewardjb4112022007-11-09 22:49:28 +0000120
121/*----------------------------------------------------------------*/
sewardjf98e1c02008-10-25 16:22:41 +0000122/*--- Primary data structures ---*/
sewardjb4112022007-11-09 22:49:28 +0000123/*----------------------------------------------------------------*/
124
sewardjb4112022007-11-09 22:49:28 +0000125/* Admin linked list of Threads */
126static Thread* admin_threads = NULL;
sewardjffce8152011-06-24 10:09:41 +0000127Thread* get_admin_threads ( void ) { return admin_threads; }
sewardjb4112022007-11-09 22:49:28 +0000128
sewardj1d7c3322011-02-28 09:22:51 +0000129/* Admin double linked list of Locks */
130/* We need a double linked list to properly and efficiently
131 handle del_LockN. */
sewardjb4112022007-11-09 22:49:28 +0000132static Lock* admin_locks = NULL;
133
sewardjb4112022007-11-09 22:49:28 +0000134/* Mapping table for core ThreadIds to Thread* */
135static Thread** map_threads = NULL; /* Array[VG_N_THREADS] of Thread* */
136
sewardjb4112022007-11-09 22:49:28 +0000137/* Mapping table for lock guest addresses to Lock* */
138static WordFM* map_locks = NULL; /* WordFM LockAddr Lock* */
139
sewardj0f64c9e2011-03-10 17:40:22 +0000140/* The word-set universes for lock sets. */
sewardjb4112022007-11-09 22:49:28 +0000141static WordSetU* univ_lsets = NULL; /* sets of Lock* */
142static WordSetU* univ_laog = NULL; /* sets of Lock*, for LAOG */
sewardj866c80c2011-10-22 19:29:51 +0000143static Int next_gc_univ_laog = 1;
144/* univ_laog will be garbaged collected when the nr of element in univ_laog is
145 >= next_gc_univ_laog. */
sewardjb4112022007-11-09 22:49:28 +0000146
sewardjffce8152011-06-24 10:09:41 +0000147/* Allow libhb to get at the universe of locksets stored
148 here. Sigh. */
149WordSetU* HG_(get_univ_lsets) ( void ) { return univ_lsets; }
150
151/* Allow libhb to get at the list of locks stored here. Ditto
152 sigh. */
153Lock* HG_(get_admin_locks) ( void ) { return admin_locks; }
154
sewardjb4112022007-11-09 22:49:28 +0000155
156/*----------------------------------------------------------------*/
157/*--- Simple helpers for the data structures ---*/
158/*----------------------------------------------------------------*/
159
160static UWord stats__lockN_acquires = 0;
161static UWord stats__lockN_releases = 0;
162
sewardjf98e1c02008-10-25 16:22:41 +0000163static
164ThreadId map_threads_maybe_reverse_lookup_SLOW ( Thread* thr ); /*fwds*/
sewardjb4112022007-11-09 22:49:28 +0000165
166/* --------- Constructors --------- */
167
sewardjf98e1c02008-10-25 16:22:41 +0000168static Thread* mk_Thread ( Thr* hbthr ) {
sewardjb4112022007-11-09 22:49:28 +0000169 static Int indx = 1;
sewardjf98e1c02008-10-25 16:22:41 +0000170 Thread* thread = HG_(zalloc)( "hg.mk_Thread.1", sizeof(Thread) );
sewardjb4112022007-11-09 22:49:28 +0000171 thread->locksetA = HG_(emptyWS)( univ_lsets );
172 thread->locksetW = HG_(emptyWS)( univ_lsets );
sewardjb4112022007-11-09 22:49:28 +0000173 thread->magic = Thread_MAGIC;
sewardjf98e1c02008-10-25 16:22:41 +0000174 thread->hbthr = hbthr;
175 thread->coretid = VG_INVALID_THREADID;
sewardjb4112022007-11-09 22:49:28 +0000176 thread->created_at = NULL;
177 thread->announced = False;
178 thread->errmsg_index = indx++;
179 thread->admin = admin_threads;
180 admin_threads = thread;
181 return thread;
182}
sewardjf98e1c02008-10-25 16:22:41 +0000183
sewardjb4112022007-11-09 22:49:28 +0000184// Make a new lock which is unlocked (hence ownerless)
sewardj1d7c3322011-02-28 09:22:51 +0000185// and insert the new lock in admin_locks double linked list.
sewardjb4112022007-11-09 22:49:28 +0000186static Lock* mk_LockN ( LockKind kind, Addr guestaddr ) {
187 static ULong unique = 0;
sewardjf98e1c02008-10-25 16:22:41 +0000188 Lock* lock = HG_(zalloc)( "hg.mk_Lock.1", sizeof(Lock) );
sewardj0f64c9e2011-03-10 17:40:22 +0000189 /* begin: add to double linked list */
sewardj1d7c3322011-02-28 09:22:51 +0000190 if (admin_locks)
191 admin_locks->admin_prev = lock;
sewardj0f64c9e2011-03-10 17:40:22 +0000192 lock->admin_next = admin_locks;
193 lock->admin_prev = NULL;
sewardj1d7c3322011-02-28 09:22:51 +0000194 admin_locks = lock;
sewardj0f64c9e2011-03-10 17:40:22 +0000195 /* end: add */
sewardjb4112022007-11-09 22:49:28 +0000196 lock->unique = unique++;
197 lock->magic = LockN_MAGIC;
198 lock->appeared_at = NULL;
199 lock->acquired_at = NULL;
sewardjf98e1c02008-10-25 16:22:41 +0000200 lock->hbso = libhb_so_alloc();
sewardjb4112022007-11-09 22:49:28 +0000201 lock->guestaddr = guestaddr;
202 lock->kind = kind;
203 lock->heldW = False;
204 lock->heldBy = NULL;
sewardjf98e1c02008-10-25 16:22:41 +0000205 tl_assert(HG_(is_sane_LockN)(lock));
sewardjb4112022007-11-09 22:49:28 +0000206 return lock;
207}
sewardjb4112022007-11-09 22:49:28 +0000208
209/* Release storage for a Lock. Also release storage in .heldBy, if
sewardj1d7c3322011-02-28 09:22:51 +0000210 any. Removes from admin_locks double linked list. */
sewardjb4112022007-11-09 22:49:28 +0000211static void del_LockN ( Lock* lk )
212{
sewardjf98e1c02008-10-25 16:22:41 +0000213 tl_assert(HG_(is_sane_LockN)(lk));
214 tl_assert(lk->hbso);
215 libhb_so_dealloc(lk->hbso);
sewardjb4112022007-11-09 22:49:28 +0000216 if (lk->heldBy)
sewardj896f6f92008-08-19 08:38:52 +0000217 VG_(deleteBag)( lk->heldBy );
sewardj0f64c9e2011-03-10 17:40:22 +0000218 /* begin: del lock from double linked list */
219 if (lk == admin_locks) {
220 tl_assert(lk->admin_prev == NULL);
221 if (lk->admin_next)
222 lk->admin_next->admin_prev = NULL;
sewardj1d7c3322011-02-28 09:22:51 +0000223 admin_locks = lk->admin_next;
sewardj1d7c3322011-02-28 09:22:51 +0000224 }
225 else {
sewardj0f64c9e2011-03-10 17:40:22 +0000226 tl_assert(lk->admin_prev != NULL);
sewardj1d7c3322011-02-28 09:22:51 +0000227 lk->admin_prev->admin_next = lk->admin_next;
sewardj0f64c9e2011-03-10 17:40:22 +0000228 if (lk->admin_next)
229 lk->admin_next->admin_prev = lk->admin_prev;
sewardj1d7c3322011-02-28 09:22:51 +0000230 }
sewardj0f64c9e2011-03-10 17:40:22 +0000231 /* end: del */
sewardjb4112022007-11-09 22:49:28 +0000232 VG_(memset)(lk, 0xAA, sizeof(*lk));
sewardjf98e1c02008-10-25 16:22:41 +0000233 HG_(free)(lk);
sewardjb4112022007-11-09 22:49:28 +0000234}
235
236/* Update 'lk' to reflect that 'thr' now has a write-acquisition of
237 it. This is done strictly: only combinations resulting from
238 correct program and libpthread behaviour are allowed. */
239static void lockN_acquire_writer ( Lock* lk, Thread* thr )
240{
sewardjf98e1c02008-10-25 16:22:41 +0000241 tl_assert(HG_(is_sane_LockN)(lk));
242 tl_assert(HG_(is_sane_Thread)(thr));
sewardjb4112022007-11-09 22:49:28 +0000243
244 stats__lockN_acquires++;
245
246 /* EXPOSITION only */
247 /* We need to keep recording snapshots of where the lock was
248 acquired, so as to produce better lock-order error messages. */
249 if (lk->acquired_at == NULL) {
250 ThreadId tid;
251 tl_assert(lk->heldBy == NULL);
252 tid = map_threads_maybe_reverse_lookup_SLOW(thr);
253 lk->acquired_at
sewardjf98e1c02008-10-25 16:22:41 +0000254 = VG_(record_ExeContext)(tid, 0/*first_ip_delta*/);
sewardjb4112022007-11-09 22:49:28 +0000255 } else {
256 tl_assert(lk->heldBy != NULL);
257 }
258 /* end EXPOSITION only */
259
260 switch (lk->kind) {
261 case LK_nonRec:
262 case_LK_nonRec:
263 tl_assert(lk->heldBy == NULL); /* can't w-lock recursively */
264 tl_assert(!lk->heldW);
265 lk->heldW = True;
sewardjf98e1c02008-10-25 16:22:41 +0000266 lk->heldBy = VG_(newBag)( HG_(zalloc), "hg.lNaw.1", HG_(free) );
florian6bf37262012-10-21 03:23:36 +0000267 VG_(addToBag)( lk->heldBy, (UWord)thr );
sewardjb4112022007-11-09 22:49:28 +0000268 break;
269 case LK_mbRec:
270 if (lk->heldBy == NULL)
271 goto case_LK_nonRec;
272 /* 2nd and subsequent locking of a lock by its owner */
273 tl_assert(lk->heldW);
274 /* assert: lk is only held by one thread .. */
sewardj896f6f92008-08-19 08:38:52 +0000275 tl_assert(VG_(sizeUniqueBag(lk->heldBy)) == 1);
sewardjb4112022007-11-09 22:49:28 +0000276 /* assert: .. and that thread is 'thr'. */
florian6bf37262012-10-21 03:23:36 +0000277 tl_assert(VG_(elemBag)(lk->heldBy, (UWord)thr)
sewardj896f6f92008-08-19 08:38:52 +0000278 == VG_(sizeTotalBag)(lk->heldBy));
florian6bf37262012-10-21 03:23:36 +0000279 VG_(addToBag)(lk->heldBy, (UWord)thr);
sewardjb4112022007-11-09 22:49:28 +0000280 break;
281 case LK_rdwr:
282 tl_assert(lk->heldBy == NULL && !lk->heldW); /* must be unheld */
283 goto case_LK_nonRec;
284 default:
285 tl_assert(0);
286 }
sewardjf98e1c02008-10-25 16:22:41 +0000287 tl_assert(HG_(is_sane_LockN)(lk));
sewardjb4112022007-11-09 22:49:28 +0000288}
289
290static void lockN_acquire_reader ( Lock* lk, Thread* thr )
291{
sewardjf98e1c02008-10-25 16:22:41 +0000292 tl_assert(HG_(is_sane_LockN)(lk));
293 tl_assert(HG_(is_sane_Thread)(thr));
sewardjb4112022007-11-09 22:49:28 +0000294 /* can only add reader to a reader-writer lock. */
295 tl_assert(lk->kind == LK_rdwr);
296 /* lk must be free or already r-held. */
297 tl_assert(lk->heldBy == NULL
298 || (lk->heldBy != NULL && !lk->heldW));
299
300 stats__lockN_acquires++;
301
302 /* EXPOSITION only */
303 /* We need to keep recording snapshots of where the lock was
304 acquired, so as to produce better lock-order error messages. */
305 if (lk->acquired_at == NULL) {
306 ThreadId tid;
307 tl_assert(lk->heldBy == NULL);
308 tid = map_threads_maybe_reverse_lookup_SLOW(thr);
309 lk->acquired_at
sewardjf98e1c02008-10-25 16:22:41 +0000310 = VG_(record_ExeContext)(tid, 0/*first_ip_delta*/);
sewardjb4112022007-11-09 22:49:28 +0000311 } else {
312 tl_assert(lk->heldBy != NULL);
313 }
314 /* end EXPOSITION only */
315
316 if (lk->heldBy) {
florian6bf37262012-10-21 03:23:36 +0000317 VG_(addToBag)(lk->heldBy, (UWord)thr);
sewardjb4112022007-11-09 22:49:28 +0000318 } else {
319 lk->heldW = False;
sewardjf98e1c02008-10-25 16:22:41 +0000320 lk->heldBy = VG_(newBag)( HG_(zalloc), "hg.lNar.1", HG_(free) );
florian6bf37262012-10-21 03:23:36 +0000321 VG_(addToBag)( lk->heldBy, (UWord)thr );
sewardjb4112022007-11-09 22:49:28 +0000322 }
323 tl_assert(!lk->heldW);
sewardjf98e1c02008-10-25 16:22:41 +0000324 tl_assert(HG_(is_sane_LockN)(lk));
sewardjb4112022007-11-09 22:49:28 +0000325}
326
327/* Update 'lk' to reflect a release of it by 'thr'. This is done
328 strictly: only combinations resulting from correct program and
329 libpthread behaviour are allowed. */
330
331static void lockN_release ( Lock* lk, Thread* thr )
332{
333 Bool b;
sewardjf98e1c02008-10-25 16:22:41 +0000334 tl_assert(HG_(is_sane_LockN)(lk));
335 tl_assert(HG_(is_sane_Thread)(thr));
sewardjb4112022007-11-09 22:49:28 +0000336 /* lock must be held by someone */
337 tl_assert(lk->heldBy);
338 stats__lockN_releases++;
339 /* Remove it from the holder set */
florian6bf37262012-10-21 03:23:36 +0000340 b = VG_(delFromBag)(lk->heldBy, (UWord)thr);
sewardjb4112022007-11-09 22:49:28 +0000341 /* thr must actually have been a holder of lk */
342 tl_assert(b);
343 /* normalise */
344 tl_assert(lk->acquired_at);
sewardj896f6f92008-08-19 08:38:52 +0000345 if (VG_(isEmptyBag)(lk->heldBy)) {
346 VG_(deleteBag)(lk->heldBy);
sewardjb4112022007-11-09 22:49:28 +0000347 lk->heldBy = NULL;
348 lk->heldW = False;
349 lk->acquired_at = NULL;
350 }
sewardjf98e1c02008-10-25 16:22:41 +0000351 tl_assert(HG_(is_sane_LockN)(lk));
sewardjb4112022007-11-09 22:49:28 +0000352}
353
354static void remove_Lock_from_locksets_of_all_owning_Threads( Lock* lk )
355{
356 Thread* thr;
357 if (!lk->heldBy) {
358 tl_assert(!lk->heldW);
359 return;
360 }
361 /* for each thread that holds this lock do ... */
sewardj896f6f92008-08-19 08:38:52 +0000362 VG_(initIterBag)( lk->heldBy );
florian6bf37262012-10-21 03:23:36 +0000363 while (VG_(nextIterBag)( lk->heldBy, (UWord*)&thr, NULL )) {
sewardjf98e1c02008-10-25 16:22:41 +0000364 tl_assert(HG_(is_sane_Thread)(thr));
sewardjb4112022007-11-09 22:49:28 +0000365 tl_assert(HG_(elemWS)( univ_lsets,
florian6bf37262012-10-21 03:23:36 +0000366 thr->locksetA, (UWord)lk ));
sewardjb4112022007-11-09 22:49:28 +0000367 thr->locksetA
florian6bf37262012-10-21 03:23:36 +0000368 = HG_(delFromWS)( univ_lsets, thr->locksetA, (UWord)lk );
sewardjb4112022007-11-09 22:49:28 +0000369
370 if (lk->heldW) {
371 tl_assert(HG_(elemWS)( univ_lsets,
florian6bf37262012-10-21 03:23:36 +0000372 thr->locksetW, (UWord)lk ));
sewardjb4112022007-11-09 22:49:28 +0000373 thr->locksetW
florian6bf37262012-10-21 03:23:36 +0000374 = HG_(delFromWS)( univ_lsets, thr->locksetW, (UWord)lk );
sewardjb4112022007-11-09 22:49:28 +0000375 }
376 }
sewardj896f6f92008-08-19 08:38:52 +0000377 VG_(doneIterBag)( lk->heldBy );
sewardjb4112022007-11-09 22:49:28 +0000378}
379
sewardjb4112022007-11-09 22:49:28 +0000380
381/*----------------------------------------------------------------*/
382/*--- Print out the primary data structures ---*/
383/*----------------------------------------------------------------*/
384
sewardjb4112022007-11-09 22:49:28 +0000385#define PP_THREADS (1<<1)
386#define PP_LOCKS (1<<2)
sewardjf98e1c02008-10-25 16:22:41 +0000387#define PP_ALL (PP_THREADS | PP_LOCKS)
sewardjb4112022007-11-09 22:49:28 +0000388
389
390static const Int sHOW_ADMIN = 0;
391
392static void space ( Int n )
393{
394 Int i;
florian6bf37262012-10-21 03:23:36 +0000395 HChar spaces[128+1];
sewardjb4112022007-11-09 22:49:28 +0000396 tl_assert(n >= 0 && n < 128);
397 if (n == 0)
398 return;
399 for (i = 0; i < n; i++)
400 spaces[i] = ' ';
401 spaces[i] = 0;
402 tl_assert(i < 128+1);
403 VG_(printf)("%s", spaces);
404}
405
406static void pp_Thread ( Int d, Thread* t )
407{
408 space(d+0); VG_(printf)("Thread %p {\n", t);
409 if (sHOW_ADMIN) {
410 space(d+3); VG_(printf)("admin %p\n", t->admin);
411 space(d+3); VG_(printf)("magic 0x%x\n", (UInt)t->magic);
412 }
413 space(d+3); VG_(printf)("locksetA %d\n", (Int)t->locksetA);
414 space(d+3); VG_(printf)("locksetW %d\n", (Int)t->locksetW);
sewardjb4112022007-11-09 22:49:28 +0000415 space(d+0); VG_(printf)("}\n");
416}
417
418static void pp_admin_threads ( Int d )
419{
420 Int i, n;
421 Thread* t;
422 for (n = 0, t = admin_threads; t; n++, t = t->admin) {
423 /* nothing */
424 }
425 space(d); VG_(printf)("admin_threads (%d records) {\n", n);
426 for (i = 0, t = admin_threads; t; i++, t = t->admin) {
427 if (0) {
428 space(n);
429 VG_(printf)("admin_threads record %d of %d:\n", i, n);
430 }
431 pp_Thread(d+3, t);
432 }
barta0b6b2c2008-07-07 06:49:24 +0000433 space(d); VG_(printf)("}\n");
sewardjb4112022007-11-09 22:49:28 +0000434}
435
436static void pp_map_threads ( Int d )
437{
njn4c245e52009-03-15 23:25:38 +0000438 Int i, n = 0;
sewardjb4112022007-11-09 22:49:28 +0000439 space(d); VG_(printf)("map_threads ");
sewardjb4112022007-11-09 22:49:28 +0000440 for (i = 0; i < VG_N_THREADS; i++) {
441 if (map_threads[i] != NULL)
442 n++;
443 }
444 VG_(printf)("(%d entries) {\n", n);
445 for (i = 0; i < VG_N_THREADS; i++) {
446 if (map_threads[i] == NULL)
447 continue;
448 space(d+3);
449 VG_(printf)("coretid %d -> Thread %p\n", i, map_threads[i]);
450 }
451 space(d); VG_(printf)("}\n");
452}
453
454static const HChar* show_LockKind ( LockKind lkk ) {
455 switch (lkk) {
456 case LK_mbRec: return "mbRec";
457 case LK_nonRec: return "nonRec";
458 case LK_rdwr: return "rdwr";
459 default: tl_assert(0);
460 }
461}
462
philippef5774342014-05-03 11:12:50 +0000463/* Pretty Print lock lk.
464 if show_lock_addrdescr, describes the (guest) lock address.
465 (this description will be more complete with --read-var-info=yes).
466 if show_internal_data, shows also helgrind internal information.
467 d is the level at which output is indented. */
468static void pp_Lock ( Int d, Lock* lk,
469 Bool show_lock_addrdescr,
470 Bool show_internal_data)
sewardjb4112022007-11-09 22:49:28 +0000471{
philippef5774342014-05-03 11:12:50 +0000472 space(d+0);
473 if (show_internal_data)
philippe07c08522014-05-14 20:39:27 +0000474 VG_(printf)("Lock %p (ga %#lx) {\n", lk, lk->guestaddr);
philippef5774342014-05-03 11:12:50 +0000475 else
philippe07c08522014-05-14 20:39:27 +0000476 VG_(printf)("Lock ga %#lx {\n", lk->guestaddr);
philippef5774342014-05-03 11:12:50 +0000477 if (!show_lock_addrdescr
philippe07c08522014-05-14 20:39:27 +0000478 || !HG_(get_and_pp_addrdescr) ((Addr) lk->guestaddr))
philippef5774342014-05-03 11:12:50 +0000479 VG_(printf)("\n");
480
sewardjb4112022007-11-09 22:49:28 +0000481 if (sHOW_ADMIN) {
sewardj1d7c3322011-02-28 09:22:51 +0000482 space(d+3); VG_(printf)("admin_n %p\n", lk->admin_next);
483 space(d+3); VG_(printf)("admin_p %p\n", lk->admin_prev);
484 space(d+3); VG_(printf)("magic 0x%x\n", (UInt)lk->magic);
sewardjb4112022007-11-09 22:49:28 +0000485 }
philippef5774342014-05-03 11:12:50 +0000486 if (show_internal_data) {
487 space(d+3); VG_(printf)("unique %llu\n", lk->unique);
488 }
sewardjb4112022007-11-09 22:49:28 +0000489 space(d+3); VG_(printf)("kind %s\n", show_LockKind(lk->kind));
philippef5774342014-05-03 11:12:50 +0000490 if (show_internal_data) {
491 space(d+3); VG_(printf)("heldW %s\n", lk->heldW ? "yes" : "no");
492 }
493 if (show_internal_data) {
494 space(d+3); VG_(printf)("heldBy %p", lk->heldBy);
495 }
sewardjb4112022007-11-09 22:49:28 +0000496 if (lk->heldBy) {
497 Thread* thr;
florian6bf37262012-10-21 03:23:36 +0000498 UWord count;
sewardjb4112022007-11-09 22:49:28 +0000499 VG_(printf)(" { ");
sewardj896f6f92008-08-19 08:38:52 +0000500 VG_(initIterBag)( lk->heldBy );
philippef5774342014-05-03 11:12:50 +0000501 while (VG_(nextIterBag)( lk->heldBy, (UWord*)&thr, &count )) {
502 if (show_internal_data)
503 VG_(printf)("%lu:%p ", count, thr);
504 else {
505 VG_(printf)("%c%lu:thread #%d ",
506 lk->heldW ? 'W' : 'R',
507 count, thr->errmsg_index);
508 if (thr->coretid == VG_INVALID_THREADID)
509 VG_(printf)("tid (exited) ");
510 else
511 VG_(printf)("tid %d ", thr->coretid);
512
513 }
514 }
sewardj896f6f92008-08-19 08:38:52 +0000515 VG_(doneIterBag)( lk->heldBy );
philippef5774342014-05-03 11:12:50 +0000516 VG_(printf)("}\n");
sewardjb4112022007-11-09 22:49:28 +0000517 }
sewardjb4112022007-11-09 22:49:28 +0000518 space(d+0); VG_(printf)("}\n");
519}
520
521static void pp_admin_locks ( Int d )
522{
523 Int i, n;
524 Lock* lk;
sewardj1d7c3322011-02-28 09:22:51 +0000525 for (n = 0, lk = admin_locks; lk; n++, lk = lk->admin_next) {
sewardjb4112022007-11-09 22:49:28 +0000526 /* nothing */
527 }
528 space(d); VG_(printf)("admin_locks (%d records) {\n", n);
sewardj1d7c3322011-02-28 09:22:51 +0000529 for (i = 0, lk = admin_locks; lk; i++, lk = lk->admin_next) {
sewardjb4112022007-11-09 22:49:28 +0000530 if (0) {
531 space(n);
532 VG_(printf)("admin_locks record %d of %d:\n", i, n);
533 }
philippef5774342014-05-03 11:12:50 +0000534 pp_Lock(d+3, lk,
535 False /* show_lock_addrdescr */,
536 True /* show_internal_data */);
sewardjb4112022007-11-09 22:49:28 +0000537 }
barta0b6b2c2008-07-07 06:49:24 +0000538 space(d); VG_(printf)("}\n");
sewardjb4112022007-11-09 22:49:28 +0000539}
540
philippef5774342014-05-03 11:12:50 +0000541static void pp_map_locks ( Int d)
sewardjb4112022007-11-09 22:49:28 +0000542{
543 void* gla;
544 Lock* lk;
545 space(d); VG_(printf)("map_locks (%d entries) {\n",
sewardj896f6f92008-08-19 08:38:52 +0000546 (Int)VG_(sizeFM)( map_locks ));
547 VG_(initIterFM)( map_locks );
florian6bf37262012-10-21 03:23:36 +0000548 while (VG_(nextIterFM)( map_locks, (UWord*)&gla,
549 (UWord*)&lk )) {
sewardjb4112022007-11-09 22:49:28 +0000550 space(d+3);
551 VG_(printf)("guest %p -> Lock %p\n", gla, lk);
552 }
sewardj896f6f92008-08-19 08:38:52 +0000553 VG_(doneIterFM)( map_locks );
sewardjb4112022007-11-09 22:49:28 +0000554 space(d); VG_(printf)("}\n");
555}
556
florian6bf37262012-10-21 03:23:36 +0000557static void pp_everything ( Int flags, const HChar* caller )
sewardjb4112022007-11-09 22:49:28 +0000558{
559 Int d = 0;
560 VG_(printf)("\n");
561 VG_(printf)("All_Data_Structures (caller = \"%s\") {\n", caller);
562 if (flags & PP_THREADS) {
563 VG_(printf)("\n");
564 pp_admin_threads(d+3);
565 VG_(printf)("\n");
566 pp_map_threads(d+3);
567 }
568 if (flags & PP_LOCKS) {
569 VG_(printf)("\n");
570 pp_admin_locks(d+3);
571 VG_(printf)("\n");
572 pp_map_locks(d+3);
573 }
sewardjb4112022007-11-09 22:49:28 +0000574
575 VG_(printf)("\n");
576 VG_(printf)("}\n");
577 VG_(printf)("\n");
578}
579
580#undef SHOW_ADMIN
581
582
583/*----------------------------------------------------------------*/
584/*--- Initialise the primary data structures ---*/
585/*----------------------------------------------------------------*/
586
sewardjf98e1c02008-10-25 16:22:41 +0000587static void initialise_data_structures ( Thr* hbthr_root )
sewardjb4112022007-11-09 22:49:28 +0000588{
sewardjb4112022007-11-09 22:49:28 +0000589 Thread* thr;
sewardjffce8152011-06-24 10:09:41 +0000590 WordSetID wsid;
sewardjb4112022007-11-09 22:49:28 +0000591
592 /* Get everything initialised and zeroed. */
593 tl_assert(admin_threads == NULL);
594 tl_assert(admin_locks == NULL);
sewardjb4112022007-11-09 22:49:28 +0000595
sewardjb4112022007-11-09 22:49:28 +0000596 tl_assert(map_threads == NULL);
sewardjf98e1c02008-10-25 16:22:41 +0000597 map_threads = HG_(zalloc)( "hg.ids.1", VG_N_THREADS * sizeof(Thread*) );
sewardjb4112022007-11-09 22:49:28 +0000598
florian6bf37262012-10-21 03:23:36 +0000599 tl_assert(sizeof(Addr) == sizeof(UWord));
sewardjb4112022007-11-09 22:49:28 +0000600 tl_assert(map_locks == NULL);
sewardjf98e1c02008-10-25 16:22:41 +0000601 map_locks = VG_(newFM)( HG_(zalloc), "hg.ids.2", HG_(free),
602 NULL/*unboxed Word cmp*/);
sewardjb4112022007-11-09 22:49:28 +0000603
sewardjb4112022007-11-09 22:49:28 +0000604 tl_assert(univ_lsets == NULL);
sewardjf98e1c02008-10-25 16:22:41 +0000605 univ_lsets = HG_(newWordSetU)( HG_(zalloc), "hg.ids.4", HG_(free),
606 8/*cacheSize*/ );
sewardjb4112022007-11-09 22:49:28 +0000607 tl_assert(univ_lsets != NULL);
sewardjffce8152011-06-24 10:09:41 +0000608 /* Ensure that univ_lsets is non-empty, with lockset zero being the
609 empty lockset. hg_errors.c relies on the assumption that
610 lockset number zero in univ_lsets is always valid. */
611 wsid = HG_(emptyWS)(univ_lsets);
612 tl_assert(wsid == 0);
sewardjb4112022007-11-09 22:49:28 +0000613
614 tl_assert(univ_laog == NULL);
sewardjc1fb9d22011-02-28 09:03:44 +0000615 if (HG_(clo_track_lockorders)) {
616 univ_laog = HG_(newWordSetU)( HG_(zalloc), "hg.ids.5 (univ_laog)",
617 HG_(free), 24/*cacheSize*/ );
618 tl_assert(univ_laog != NULL);
619 }
sewardjb4112022007-11-09 22:49:28 +0000620
621 /* Set up entries for the root thread */
622 // FIXME: this assumes that the first real ThreadId is 1
623
sewardjb4112022007-11-09 22:49:28 +0000624 /* a Thread for the new thread ... */
sewardjf98e1c02008-10-25 16:22:41 +0000625 thr = mk_Thread(hbthr_root);
626 thr->coretid = 1; /* FIXME: hardwires an assumption about the
627 identity of the root thread. */
sewardj60626642011-03-10 15:14:37 +0000628 tl_assert( libhb_get_Thr_hgthread(hbthr_root) == NULL );
629 libhb_set_Thr_hgthread(hbthr_root, thr);
sewardjb4112022007-11-09 22:49:28 +0000630
sewardjf98e1c02008-10-25 16:22:41 +0000631 /* and bind it in the thread-map table. */
632 tl_assert(HG_(is_sane_ThreadId)(thr->coretid));
633 tl_assert(thr->coretid != VG_INVALID_THREADID);
sewardjb4112022007-11-09 22:49:28 +0000634
sewardjf98e1c02008-10-25 16:22:41 +0000635 map_threads[thr->coretid] = thr;
sewardjb4112022007-11-09 22:49:28 +0000636
637 tl_assert(VG_INVALID_THREADID == 0);
638
sewardjb4112022007-11-09 22:49:28 +0000639 all__sanity_check("initialise_data_structures");
640}
641
642
643/*----------------------------------------------------------------*/
sewardjf98e1c02008-10-25 16:22:41 +0000644/*--- map_threads :: array[core-ThreadId] of Thread* ---*/
sewardjb4112022007-11-09 22:49:28 +0000645/*----------------------------------------------------------------*/
646
647/* Doesn't assert if the relevant map_threads entry is NULL. */
648static Thread* map_threads_maybe_lookup ( ThreadId coretid )
649{
650 Thread* thr;
sewardjf98e1c02008-10-25 16:22:41 +0000651 tl_assert( HG_(is_sane_ThreadId)(coretid) );
sewardjb4112022007-11-09 22:49:28 +0000652 thr = map_threads[coretid];
653 return thr;
654}
655
656/* Asserts if the relevant map_threads entry is NULL. */
657static inline Thread* map_threads_lookup ( ThreadId coretid )
658{
659 Thread* thr;
sewardjf98e1c02008-10-25 16:22:41 +0000660 tl_assert( HG_(is_sane_ThreadId)(coretid) );
sewardjb4112022007-11-09 22:49:28 +0000661 thr = map_threads[coretid];
662 tl_assert(thr);
663 return thr;
664}
665
sewardjf98e1c02008-10-25 16:22:41 +0000666/* Do a reverse lookup. Does not assert if 'thr' is not found in
667 map_threads. */
sewardjb4112022007-11-09 22:49:28 +0000668static ThreadId map_threads_maybe_reverse_lookup_SLOW ( Thread* thr )
669{
sewardjf98e1c02008-10-25 16:22:41 +0000670 ThreadId tid;
671 tl_assert(HG_(is_sane_Thread)(thr));
sewardjb4112022007-11-09 22:49:28 +0000672 /* Check nobody used the invalid-threadid slot */
673 tl_assert(VG_INVALID_THREADID >= 0 && VG_INVALID_THREADID < VG_N_THREADS);
674 tl_assert(map_threads[VG_INVALID_THREADID] == NULL);
sewardjf98e1c02008-10-25 16:22:41 +0000675 tid = thr->coretid;
676 tl_assert(HG_(is_sane_ThreadId)(tid));
677 return tid;
sewardjb4112022007-11-09 22:49:28 +0000678}
679
680/* Do a reverse lookup. Warning: POTENTIALLY SLOW. Asserts if 'thr'
681 is not found in map_threads. */
682static ThreadId map_threads_reverse_lookup_SLOW ( Thread* thr )
683{
684 ThreadId tid = map_threads_maybe_reverse_lookup_SLOW( thr );
685 tl_assert(tid != VG_INVALID_THREADID);
sewardjf98e1c02008-10-25 16:22:41 +0000686 tl_assert(map_threads[tid]);
687 tl_assert(map_threads[tid]->coretid == tid);
sewardjb4112022007-11-09 22:49:28 +0000688 return tid;
689}
690
691static void map_threads_delete ( ThreadId coretid )
692{
693 Thread* thr;
694 tl_assert(coretid != 0);
sewardjf98e1c02008-10-25 16:22:41 +0000695 tl_assert( HG_(is_sane_ThreadId)(coretid) );
sewardjb4112022007-11-09 22:49:28 +0000696 thr = map_threads[coretid];
697 tl_assert(thr);
698 map_threads[coretid] = NULL;
699}
700
701
702/*----------------------------------------------------------------*/
703/*--- map_locks :: WordFM guest-Addr-of-lock Lock* ---*/
704/*----------------------------------------------------------------*/
705
706/* Make sure there is a lock table entry for the given (lock) guest
707 address. If not, create one of the stated 'kind' in unheld state.
708 In any case, return the address of the existing or new Lock. */
709static
710Lock* map_locks_lookup_or_create ( LockKind lkk, Addr ga, ThreadId tid )
711{
712 Bool found;
713 Lock* oldlock = NULL;
sewardjf98e1c02008-10-25 16:22:41 +0000714 tl_assert(HG_(is_sane_ThreadId)(tid));
sewardj896f6f92008-08-19 08:38:52 +0000715 found = VG_(lookupFM)( map_locks,
florian6bf37262012-10-21 03:23:36 +0000716 NULL, (UWord*)&oldlock, (UWord)ga );
sewardjb4112022007-11-09 22:49:28 +0000717 if (!found) {
718 Lock* lock = mk_LockN(lkk, ga);
719 lock->appeared_at = VG_(record_ExeContext)( tid, 0 );
sewardjf98e1c02008-10-25 16:22:41 +0000720 tl_assert(HG_(is_sane_LockN)(lock));
florian6bf37262012-10-21 03:23:36 +0000721 VG_(addToFM)( map_locks, (UWord)ga, (UWord)lock );
sewardjb4112022007-11-09 22:49:28 +0000722 tl_assert(oldlock == NULL);
sewardjb4112022007-11-09 22:49:28 +0000723 return lock;
724 } else {
725 tl_assert(oldlock != NULL);
sewardjf98e1c02008-10-25 16:22:41 +0000726 tl_assert(HG_(is_sane_LockN)(oldlock));
sewardjb4112022007-11-09 22:49:28 +0000727 tl_assert(oldlock->guestaddr == ga);
sewardjb4112022007-11-09 22:49:28 +0000728 return oldlock;
729 }
730}
731
732static Lock* map_locks_maybe_lookup ( Addr ga )
733{
734 Bool found;
735 Lock* lk = NULL;
florian6bf37262012-10-21 03:23:36 +0000736 found = VG_(lookupFM)( map_locks, NULL, (UWord*)&lk, (UWord)ga );
sewardjb4112022007-11-09 22:49:28 +0000737 tl_assert(found ? lk != NULL : lk == NULL);
sewardjb4112022007-11-09 22:49:28 +0000738 return lk;
739}
740
741static void map_locks_delete ( Addr ga )
742{
743 Addr ga2 = 0;
744 Lock* lk = NULL;
sewardj896f6f92008-08-19 08:38:52 +0000745 VG_(delFromFM)( map_locks,
florian6bf37262012-10-21 03:23:36 +0000746 (UWord*)&ga2, (UWord*)&lk, (UWord)ga );
sewardjb4112022007-11-09 22:49:28 +0000747 /* delFromFM produces the val which is being deleted, if it is
748 found. So assert it is non-null; that in effect asserts that we
749 are deleting a (ga, Lock) pair which actually exists. */
750 tl_assert(lk != NULL);
751 tl_assert(ga2 == ga);
752}
753
754
sewardjb4112022007-11-09 22:49:28 +0000755
756/*----------------------------------------------------------------*/
757/*--- Sanity checking the data structures ---*/
758/*----------------------------------------------------------------*/
759
760static UWord stats__sanity_checks = 0;
761
florian6bf37262012-10-21 03:23:36 +0000762static void laog__sanity_check ( const HChar* who ); /* fwds */
sewardjb4112022007-11-09 22:49:28 +0000763
764/* REQUIRED INVARIANTS:
765
766 Thread vs Segment/Lock/SecMaps
767
768 for each t in Threads {
769
770 // Thread.lockset: each element is really a valid Lock
771
772 // Thread.lockset: each Lock in set is actually held by that thread
773 for lk in Thread.lockset
774 lk == LockedBy(t)
775
776 // Thread.csegid is a valid SegmentID
777 // and the associated Segment has .thr == t
778
779 }
780
781 all thread Locksets are pairwise empty under intersection
782 (that is, no lock is claimed to be held by more than one thread)
783 -- this is guaranteed if all locks in locksets point back to their
784 owner threads
785
786 Lock vs Thread/Segment/SecMaps
787
788 for each entry (gla, la) in map_locks
789 gla == la->guest_addr
790
791 for each lk in Locks {
792
793 lk->tag is valid
794 lk->guest_addr does not have shadow state NoAccess
795 if lk == LockedBy(t), then t->lockset contains lk
796 if lk == UnlockedBy(segid) then segid is valid SegmentID
797 and can be mapped to a valid Segment(seg)
798 and seg->thr->lockset does not contain lk
799 if lk == UnlockedNew then (no lockset contains lk)
800
801 secmaps for lk has .mbHasLocks == True
802
803 }
804
805 Segment vs Thread/Lock/SecMaps
806
807 the Segment graph is a dag (no cycles)
808 all of the Segment graph must be reachable from the segids
809 mentioned in the Threads
810
811 for seg in Segments {
812
813 seg->thr is a sane Thread
814
815 }
816
817 SecMaps vs Segment/Thread/Lock
818
819 for sm in SecMaps {
820
821 sm properly aligned
822 if any shadow word is ShR or ShM then .mbHasShared == True
823
824 for each Excl(segid) state
825 map_segments_lookup maps to a sane Segment(seg)
826 for each ShM/ShR(tsetid,lsetid) state
827 each lk in lset is a valid Lock
828 each thr in tset is a valid thread, which is non-dead
829
830 }
831*/
832
833
834/* Return True iff 'thr' holds 'lk' in some mode. */
835static Bool thread_is_a_holder_of_Lock ( Thread* thr, Lock* lk )
836{
837 if (lk->heldBy)
florian6bf37262012-10-21 03:23:36 +0000838 return VG_(elemBag)( lk->heldBy, (UWord)thr ) > 0;
sewardjb4112022007-11-09 22:49:28 +0000839 else
840 return False;
841}
842
843/* Sanity check Threads, as far as possible */
844__attribute__((noinline))
florian6bf37262012-10-21 03:23:36 +0000845static void threads__sanity_check ( const HChar* who )
sewardjb4112022007-11-09 22:49:28 +0000846{
847#define BAD(_str) do { how = (_str); goto bad; } while (0)
florian6bf37262012-10-21 03:23:36 +0000848 const HChar* how = "no error";
sewardjb4112022007-11-09 22:49:28 +0000849 Thread* thr;
850 WordSetID wsA, wsW;
sewardj250ec2e2008-02-15 22:02:30 +0000851 UWord* ls_words;
florian6bf37262012-10-21 03:23:36 +0000852 UWord ls_size, i;
sewardjb4112022007-11-09 22:49:28 +0000853 Lock* lk;
sewardjb4112022007-11-09 22:49:28 +0000854 for (thr = admin_threads; thr; thr = thr->admin) {
sewardjf98e1c02008-10-25 16:22:41 +0000855 if (!HG_(is_sane_Thread)(thr)) BAD("1");
sewardjb4112022007-11-09 22:49:28 +0000856 wsA = thr->locksetA;
857 wsW = thr->locksetW;
858 // locks held in W mode are a subset of all locks held
859 if (!HG_(isSubsetOf)( univ_lsets, wsW, wsA )) BAD("7");
860 HG_(getPayloadWS)( &ls_words, &ls_size, univ_lsets, wsA );
861 for (i = 0; i < ls_size; i++) {
862 lk = (Lock*)ls_words[i];
863 // Thread.lockset: each element is really a valid Lock
sewardjf98e1c02008-10-25 16:22:41 +0000864 if (!HG_(is_sane_LockN)(lk)) BAD("2");
sewardjb4112022007-11-09 22:49:28 +0000865 // Thread.lockset: each Lock in set is actually held by that
866 // thread
867 if (!thread_is_a_holder_of_Lock(thr,lk)) BAD("3");
sewardjb4112022007-11-09 22:49:28 +0000868 }
869 }
870 return;
871 bad:
872 VG_(printf)("threads__sanity_check: who=\"%s\", bad=\"%s\"\n", who, how);
873 tl_assert(0);
874#undef BAD
875}
876
877
878/* Sanity check Locks, as far as possible */
879__attribute__((noinline))
florian6bf37262012-10-21 03:23:36 +0000880static void locks__sanity_check ( const HChar* who )
sewardjb4112022007-11-09 22:49:28 +0000881{
882#define BAD(_str) do { how = (_str); goto bad; } while (0)
florian6bf37262012-10-21 03:23:36 +0000883 const HChar* how = "no error";
sewardjb4112022007-11-09 22:49:28 +0000884 Addr gla;
885 Lock* lk;
886 Int i;
887 // # entries in admin_locks == # entries in map_locks
sewardj1d7c3322011-02-28 09:22:51 +0000888 for (i = 0, lk = admin_locks; lk; i++, lk = lk->admin_next)
sewardjb4112022007-11-09 22:49:28 +0000889 ;
sewardj896f6f92008-08-19 08:38:52 +0000890 if (i != VG_(sizeFM)(map_locks)) BAD("1");
sewardjb4112022007-11-09 22:49:28 +0000891 // for each entry (gla, lk) in map_locks
892 // gla == lk->guest_addr
sewardj896f6f92008-08-19 08:38:52 +0000893 VG_(initIterFM)( map_locks );
894 while (VG_(nextIterFM)( map_locks,
florian6bf37262012-10-21 03:23:36 +0000895 (UWord*)&gla, (UWord*)&lk )) {
sewardjb4112022007-11-09 22:49:28 +0000896 if (lk->guestaddr != gla) BAD("2");
897 }
sewardj896f6f92008-08-19 08:38:52 +0000898 VG_(doneIterFM)( map_locks );
sewardjb4112022007-11-09 22:49:28 +0000899 // scan through admin_locks ...
sewardj1d7c3322011-02-28 09:22:51 +0000900 for (lk = admin_locks; lk; lk = lk->admin_next) {
sewardjb4112022007-11-09 22:49:28 +0000901 // lock is sane. Quite comprehensive, also checks that
902 // referenced (holder) threads are sane.
sewardjf98e1c02008-10-25 16:22:41 +0000903 if (!HG_(is_sane_LockN)(lk)) BAD("3");
sewardjb4112022007-11-09 22:49:28 +0000904 // map_locks binds guest address back to this lock
905 if (lk != map_locks_maybe_lookup(lk->guestaddr)) BAD("4");
sewardjb4112022007-11-09 22:49:28 +0000906 // look at all threads mentioned as holders of this lock. Ensure
907 // this lock is mentioned in their locksets.
908 if (lk->heldBy) {
909 Thread* thr;
florian6bf37262012-10-21 03:23:36 +0000910 UWord count;
sewardj896f6f92008-08-19 08:38:52 +0000911 VG_(initIterBag)( lk->heldBy );
912 while (VG_(nextIterBag)( lk->heldBy,
florian6bf37262012-10-21 03:23:36 +0000913 (UWord*)&thr, &count )) {
sewardjf98e1c02008-10-25 16:22:41 +0000914 // HG_(is_sane_LockN) above ensures these
sewardjb4112022007-11-09 22:49:28 +0000915 tl_assert(count >= 1);
sewardjf98e1c02008-10-25 16:22:41 +0000916 tl_assert(HG_(is_sane_Thread)(thr));
florian6bf37262012-10-21 03:23:36 +0000917 if (!HG_(elemWS)(univ_lsets, thr->locksetA, (UWord)lk))
sewardjb4112022007-11-09 22:49:28 +0000918 BAD("6");
919 // also check the w-only lockset
920 if (lk->heldW
florian6bf37262012-10-21 03:23:36 +0000921 && !HG_(elemWS)(univ_lsets, thr->locksetW, (UWord)lk))
sewardjb4112022007-11-09 22:49:28 +0000922 BAD("7");
923 if ((!lk->heldW)
florian6bf37262012-10-21 03:23:36 +0000924 && HG_(elemWS)(univ_lsets, thr->locksetW, (UWord)lk))
sewardjb4112022007-11-09 22:49:28 +0000925 BAD("8");
926 }
sewardj896f6f92008-08-19 08:38:52 +0000927 VG_(doneIterBag)( lk->heldBy );
sewardjb4112022007-11-09 22:49:28 +0000928 } else {
929 /* lock not held by anybody */
930 if (lk->heldW) BAD("9"); /* should be False if !heldBy */
931 // since lk is unheld, then (no lockset contains lk)
932 // hmm, this is really too expensive to check. Hmm.
933 }
sewardjb4112022007-11-09 22:49:28 +0000934 }
935
936 return;
937 bad:
938 VG_(printf)("locks__sanity_check: who=\"%s\", bad=\"%s\"\n", who, how);
939 tl_assert(0);
940#undef BAD
941}
942
943
florian6bf37262012-10-21 03:23:36 +0000944static void all_except_Locks__sanity_check ( const HChar* who ) {
sewardjb4112022007-11-09 22:49:28 +0000945 stats__sanity_checks++;
946 if (0) VG_(printf)("all_except_Locks__sanity_check(%s)\n", who);
947 threads__sanity_check(who);
sewardjc1fb9d22011-02-28 09:03:44 +0000948 if (HG_(clo_track_lockorders))
949 laog__sanity_check(who);
sewardjb4112022007-11-09 22:49:28 +0000950}
florian6bf37262012-10-21 03:23:36 +0000951static void all__sanity_check ( const HChar* who ) {
sewardjb4112022007-11-09 22:49:28 +0000952 all_except_Locks__sanity_check(who);
953 locks__sanity_check(who);
954}
955
956
957/*----------------------------------------------------------------*/
sewardjb4112022007-11-09 22:49:28 +0000958/*--- Shadow value and address range handlers ---*/
959/*----------------------------------------------------------------*/
960
961static void laog__pre_thread_acquires_lock ( Thread*, Lock* ); /* fwds */
sewardj1cbc12f2008-11-10 16:16:46 +0000962//static void laog__handle_lock_deletions ( WordSetID ); /* fwds */
sewardjb4112022007-11-09 22:49:28 +0000963static inline Thread* get_current_Thread ( void ); /* fwds */
sewardj1cbc12f2008-11-10 16:16:46 +0000964__attribute__((noinline))
965static void laog__handle_one_lock_deletion ( Lock* lk ); /* fwds */
sewardjb4112022007-11-09 22:49:28 +0000966
sewardjb4112022007-11-09 22:49:28 +0000967
968/* Block-copy states (needed for implementing realloc()). */
sewardj23f12002009-07-24 08:45:08 +0000969/* FIXME this copies shadow memory; it doesn't apply the MSM to it.
970 Is that a problem? (hence 'scopy' rather than 'ccopy') */
971static void shadow_mem_scopy_range ( Thread* thr,
972 Addr src, Addr dst, SizeT len )
sewardjf98e1c02008-10-25 16:22:41 +0000973{
974 Thr* hbthr = thr->hbthr;
975 tl_assert(hbthr);
sewardj23f12002009-07-24 08:45:08 +0000976 libhb_copy_shadow_state( hbthr, src, dst, len );
sewardjb4112022007-11-09 22:49:28 +0000977}
978
sewardj23f12002009-07-24 08:45:08 +0000979static void shadow_mem_cread_range ( Thread* thr, Addr a, SizeT len )
980{
sewardjf98e1c02008-10-25 16:22:41 +0000981 Thr* hbthr = thr->hbthr;
982 tl_assert(hbthr);
sewardj23f12002009-07-24 08:45:08 +0000983 LIBHB_CREAD_N(hbthr, a, len);
984}
985
986static void shadow_mem_cwrite_range ( Thread* thr, Addr a, SizeT len ) {
987 Thr* hbthr = thr->hbthr;
988 tl_assert(hbthr);
989 LIBHB_CWRITE_N(hbthr, a, len);
sewardjb4112022007-11-09 22:49:28 +0000990}
991
992static void shadow_mem_make_New ( Thread* thr, Addr a, SizeT len )
993{
sewardj23f12002009-07-24 08:45:08 +0000994 libhb_srange_new( thr->hbthr, a, len );
sewardjb4112022007-11-09 22:49:28 +0000995}
996
sewardjfd35d492011-03-17 19:39:55 +0000997static void shadow_mem_make_NoAccess_NoFX ( Thread* thr, Addr aIN, SizeT len )
sewardjb4112022007-11-09 22:49:28 +0000998{
sewardjb4112022007-11-09 22:49:28 +0000999 if (0 && len > 500)
sewardjfd35d492011-03-17 19:39:55 +00001000 VG_(printf)("make NoAccess_NoFX ( %#lx, %ld )\n", aIN, len );
1001 // has no effect (NoFX)
1002 libhb_srange_noaccess_NoFX( thr->hbthr, aIN, len );
1003}
1004
1005static void shadow_mem_make_NoAccess_AHAE ( Thread* thr, Addr aIN, SizeT len )
1006{
1007 if (0 && len > 500)
1008 VG_(printf)("make NoAccess_AHAE ( %#lx, %ld )\n", aIN, len );
1009 // Actually Has An Effect (AHAE)
1010 libhb_srange_noaccess_AHAE( thr->hbthr, aIN, len );
sewardjb4112022007-11-09 22:49:28 +00001011}
1012
sewardj406bac82010-03-03 23:03:40 +00001013static void shadow_mem_make_Untracked ( Thread* thr, Addr aIN, SizeT len )
1014{
1015 if (0 && len > 500)
1016 VG_(printf)("make Untracked ( %#lx, %ld )\n", aIN, len );
1017 libhb_srange_untrack( thr->hbthr, aIN, len );
1018}
1019
sewardjb4112022007-11-09 22:49:28 +00001020
1021/*----------------------------------------------------------------*/
1022/*--- Event handlers (evh__* functions) ---*/
1023/*--- plus helpers (evhH__* functions) ---*/
1024/*----------------------------------------------------------------*/
1025
1026/*--------- Event handler helpers (evhH__* functions) ---------*/
1027
1028/* Create a new segment for 'thr', making it depend (.prev) on its
1029 existing segment, bind together the SegmentID and Segment, and
1030 return both of them. Also update 'thr' so it references the new
1031 Segment. */
sewardjf98e1c02008-10-25 16:22:41 +00001032//zz static
1033//zz void evhH__start_new_segment_for_thread ( /*OUT*/SegmentID* new_segidP,
1034//zz /*OUT*/Segment** new_segP,
1035//zz Thread* thr )
1036//zz {
1037//zz Segment* cur_seg;
1038//zz tl_assert(new_segP);
1039//zz tl_assert(new_segidP);
1040//zz tl_assert(HG_(is_sane_Thread)(thr));
1041//zz cur_seg = map_segments_lookup( thr->csegid );
1042//zz tl_assert(cur_seg);
1043//zz tl_assert(cur_seg->thr == thr); /* all sane segs should point back
1044//zz at their owner thread. */
1045//zz *new_segP = mk_Segment( thr, cur_seg, NULL/*other*/ );
1046//zz *new_segidP = alloc_SegmentID();
1047//zz map_segments_add( *new_segidP, *new_segP );
1048//zz thr->csegid = *new_segidP;
1049//zz }
sewardjb4112022007-11-09 22:49:28 +00001050
1051
1052/* The lock at 'lock_ga' has acquired a writer. Make all necessary
1053 updates, and also do all possible error checks. */
1054static
1055void evhH__post_thread_w_acquires_lock ( Thread* thr,
1056 LockKind lkk, Addr lock_ga )
1057{
1058 Lock* lk;
1059
1060 /* Basically what we need to do is call lockN_acquire_writer.
1061 However, that will barf if any 'invalid' lock states would
1062 result. Therefore check before calling. Side effect is that
sewardjf98e1c02008-10-25 16:22:41 +00001063 'HG_(is_sane_LockN)(lk)' is both a pre- and post-condition of this
sewardjb4112022007-11-09 22:49:28 +00001064 routine.
1065
1066 Because this routine is only called after successful lock
1067 acquisition, we should not be asked to move the lock into any
1068 invalid states. Requests to do so are bugs in libpthread, since
1069 that should have rejected any such requests. */
1070
sewardjf98e1c02008-10-25 16:22:41 +00001071 tl_assert(HG_(is_sane_Thread)(thr));
sewardjb4112022007-11-09 22:49:28 +00001072 /* Try to find the lock. If we can't, then create a new one with
1073 kind 'lkk'. */
1074 lk = map_locks_lookup_or_create(
1075 lkk, lock_ga, map_threads_reverse_lookup_SLOW(thr) );
sewardjf98e1c02008-10-25 16:22:41 +00001076 tl_assert( HG_(is_sane_LockN)(lk) );
1077
1078 /* check libhb level entities exist */
1079 tl_assert(thr->hbthr);
1080 tl_assert(lk->hbso);
sewardjb4112022007-11-09 22:49:28 +00001081
1082 if (lk->heldBy == NULL) {
1083 /* the lock isn't held. Simple. */
1084 tl_assert(!lk->heldW);
1085 lockN_acquire_writer( lk, thr );
sewardjf98e1c02008-10-25 16:22:41 +00001086 /* acquire a dependency from the lock's VCs */
1087 libhb_so_recv( thr->hbthr, lk->hbso, True/*strong_recv*/ );
sewardjb4112022007-11-09 22:49:28 +00001088 goto noerror;
1089 }
1090
1091 /* So the lock is already held. If held as a r-lock then
1092 libpthread must be buggy. */
1093 tl_assert(lk->heldBy);
1094 if (!lk->heldW) {
sewardjf98e1c02008-10-25 16:22:41 +00001095 HG_(record_error_Misc)(
1096 thr, "Bug in libpthread: write lock "
1097 "granted on rwlock which is currently rd-held");
sewardjb4112022007-11-09 22:49:28 +00001098 goto error;
1099 }
1100
1101 /* So the lock is held in w-mode. If it's held by some other
1102 thread, then libpthread must be buggy. */
sewardj896f6f92008-08-19 08:38:52 +00001103 tl_assert(VG_(sizeUniqueBag)(lk->heldBy) == 1); /* from precondition */
sewardjb4112022007-11-09 22:49:28 +00001104
sewardj896f6f92008-08-19 08:38:52 +00001105 if (thr != (Thread*)VG_(anyElementOfBag)(lk->heldBy)) {
sewardjf98e1c02008-10-25 16:22:41 +00001106 HG_(record_error_Misc)(
1107 thr, "Bug in libpthread: write lock "
1108 "granted on mutex/rwlock which is currently "
1109 "wr-held by a different thread");
sewardjb4112022007-11-09 22:49:28 +00001110 goto error;
1111 }
1112
1113 /* So the lock is already held in w-mode by 'thr'. That means this
1114 is an attempt to lock it recursively, which is only allowable
1115 for LK_mbRec kinded locks. Since this routine is called only
1116 once the lock has been acquired, this must also be a libpthread
1117 bug. */
1118 if (lk->kind != LK_mbRec) {
sewardjf98e1c02008-10-25 16:22:41 +00001119 HG_(record_error_Misc)(
1120 thr, "Bug in libpthread: recursive write lock "
1121 "granted on mutex/wrlock which does not "
1122 "support recursion");
sewardjb4112022007-11-09 22:49:28 +00001123 goto error;
1124 }
1125
1126 /* So we are recursively re-locking a lock we already w-hold. */
1127 lockN_acquire_writer( lk, thr );
sewardjf98e1c02008-10-25 16:22:41 +00001128 /* acquire a dependency from the lock's VC. Probably pointless,
1129 but also harmless. */
1130 libhb_so_recv( thr->hbthr, lk->hbso, True/*strong_recv*/ );
sewardjb4112022007-11-09 22:49:28 +00001131 goto noerror;
1132
1133 noerror:
sewardjc1fb9d22011-02-28 09:03:44 +00001134 if (HG_(clo_track_lockorders)) {
1135 /* check lock order acquisition graph, and update. This has to
1136 happen before the lock is added to the thread's locksetA/W. */
1137 laog__pre_thread_acquires_lock( thr, lk );
1138 }
sewardjb4112022007-11-09 22:49:28 +00001139 /* update the thread's held-locks set */
florian6bf37262012-10-21 03:23:36 +00001140 thr->locksetA = HG_(addToWS)( univ_lsets, thr->locksetA, (UWord)lk );
1141 thr->locksetW = HG_(addToWS)( univ_lsets, thr->locksetW, (UWord)lk );
sewardjb4112022007-11-09 22:49:28 +00001142 /* fall through */
1143
1144 error:
sewardjf98e1c02008-10-25 16:22:41 +00001145 tl_assert(HG_(is_sane_LockN)(lk));
sewardjb4112022007-11-09 22:49:28 +00001146}
1147
1148
1149/* The lock at 'lock_ga' has acquired a reader. Make all necessary
1150 updates, and also do all possible error checks. */
1151static
1152void evhH__post_thread_r_acquires_lock ( Thread* thr,
1153 LockKind lkk, Addr lock_ga )
1154{
1155 Lock* lk;
1156
1157 /* Basically what we need to do is call lockN_acquire_reader.
1158 However, that will barf if any 'invalid' lock states would
1159 result. Therefore check before calling. Side effect is that
sewardjf98e1c02008-10-25 16:22:41 +00001160 'HG_(is_sane_LockN)(lk)' is both a pre- and post-condition of this
sewardjb4112022007-11-09 22:49:28 +00001161 routine.
1162
1163 Because this routine is only called after successful lock
1164 acquisition, we should not be asked to move the lock into any
1165 invalid states. Requests to do so are bugs in libpthread, since
1166 that should have rejected any such requests. */
1167
sewardjf98e1c02008-10-25 16:22:41 +00001168 tl_assert(HG_(is_sane_Thread)(thr));
sewardjb4112022007-11-09 22:49:28 +00001169 /* Try to find the lock. If we can't, then create a new one with
1170 kind 'lkk'. Only a reader-writer lock can be read-locked,
1171 hence the first assertion. */
1172 tl_assert(lkk == LK_rdwr);
1173 lk = map_locks_lookup_or_create(
1174 lkk, lock_ga, map_threads_reverse_lookup_SLOW(thr) );
sewardjf98e1c02008-10-25 16:22:41 +00001175 tl_assert( HG_(is_sane_LockN)(lk) );
1176
1177 /* check libhb level entities exist */
1178 tl_assert(thr->hbthr);
1179 tl_assert(lk->hbso);
sewardjb4112022007-11-09 22:49:28 +00001180
1181 if (lk->heldBy == NULL) {
1182 /* the lock isn't held. Simple. */
1183 tl_assert(!lk->heldW);
1184 lockN_acquire_reader( lk, thr );
sewardjf98e1c02008-10-25 16:22:41 +00001185 /* acquire a dependency from the lock's VC */
1186 libhb_so_recv( thr->hbthr, lk->hbso, False/*!strong_recv*/ );
sewardjb4112022007-11-09 22:49:28 +00001187 goto noerror;
1188 }
1189
1190 /* So the lock is already held. If held as a w-lock then
1191 libpthread must be buggy. */
1192 tl_assert(lk->heldBy);
1193 if (lk->heldW) {
sewardjf98e1c02008-10-25 16:22:41 +00001194 HG_(record_error_Misc)( thr, "Bug in libpthread: read lock "
1195 "granted on rwlock which is "
1196 "currently wr-held");
sewardjb4112022007-11-09 22:49:28 +00001197 goto error;
1198 }
1199
1200 /* Easy enough. In short anybody can get a read-lock on a rwlock
1201 provided it is either unlocked or already in rd-held. */
1202 lockN_acquire_reader( lk, thr );
sewardjf98e1c02008-10-25 16:22:41 +00001203 /* acquire a dependency from the lock's VC. Probably pointless,
1204 but also harmless. */
1205 libhb_so_recv( thr->hbthr, lk->hbso, False/*!strong_recv*/ );
sewardjb4112022007-11-09 22:49:28 +00001206 goto noerror;
1207
1208 noerror:
sewardjc1fb9d22011-02-28 09:03:44 +00001209 if (HG_(clo_track_lockorders)) {
1210 /* check lock order acquisition graph, and update. This has to
1211 happen before the lock is added to the thread's locksetA/W. */
1212 laog__pre_thread_acquires_lock( thr, lk );
1213 }
sewardjb4112022007-11-09 22:49:28 +00001214 /* update the thread's held-locks set */
florian6bf37262012-10-21 03:23:36 +00001215 thr->locksetA = HG_(addToWS)( univ_lsets, thr->locksetA, (UWord)lk );
sewardjb4112022007-11-09 22:49:28 +00001216 /* but don't update thr->locksetW, since lk is only rd-held */
1217 /* fall through */
1218
1219 error:
sewardjf98e1c02008-10-25 16:22:41 +00001220 tl_assert(HG_(is_sane_LockN)(lk));
sewardjb4112022007-11-09 22:49:28 +00001221}
1222
1223
1224/* The lock at 'lock_ga' is just about to be unlocked. Make all
1225 necessary updates, and also do all possible error checks. */
1226static
1227void evhH__pre_thread_releases_lock ( Thread* thr,
1228 Addr lock_ga, Bool isRDWR )
1229{
1230 Lock* lock;
1231 Word n;
sewardjf98e1c02008-10-25 16:22:41 +00001232 Bool was_heldW;
sewardjb4112022007-11-09 22:49:28 +00001233
1234 /* This routine is called prior to a lock release, before
1235 libpthread has had a chance to validate the call. Hence we need
1236 to detect and reject any attempts to move the lock into an
1237 invalid state. Such attempts are bugs in the client.
1238
1239 isRDWR is True if we know from the wrapper context that lock_ga
1240 should refer to a reader-writer lock, and is False if [ditto]
1241 lock_ga should refer to a standard mutex. */
1242
sewardjf98e1c02008-10-25 16:22:41 +00001243 tl_assert(HG_(is_sane_Thread)(thr));
sewardjb4112022007-11-09 22:49:28 +00001244 lock = map_locks_maybe_lookup( lock_ga );
1245
1246 if (!lock) {
1247 /* We know nothing about a lock at 'lock_ga'. Nevertheless
1248 the client is trying to unlock it. So complain, then ignore
1249 the attempt. */
sewardjf98e1c02008-10-25 16:22:41 +00001250 HG_(record_error_UnlockBogus)( thr, lock_ga );
sewardjb4112022007-11-09 22:49:28 +00001251 return;
1252 }
1253
1254 tl_assert(lock->guestaddr == lock_ga);
sewardjf98e1c02008-10-25 16:22:41 +00001255 tl_assert(HG_(is_sane_LockN)(lock));
sewardjb4112022007-11-09 22:49:28 +00001256
1257 if (isRDWR && lock->kind != LK_rdwr) {
sewardjf98e1c02008-10-25 16:22:41 +00001258 HG_(record_error_Misc)( thr, "pthread_rwlock_unlock with a "
1259 "pthread_mutex_t* argument " );
sewardjb4112022007-11-09 22:49:28 +00001260 }
1261 if ((!isRDWR) && lock->kind == LK_rdwr) {
sewardjf98e1c02008-10-25 16:22:41 +00001262 HG_(record_error_Misc)( thr, "pthread_mutex_unlock with a "
1263 "pthread_rwlock_t* argument " );
sewardjb4112022007-11-09 22:49:28 +00001264 }
1265
1266 if (!lock->heldBy) {
1267 /* The lock is not held. This indicates a serious bug in the
1268 client. */
1269 tl_assert(!lock->heldW);
sewardjf98e1c02008-10-25 16:22:41 +00001270 HG_(record_error_UnlockUnlocked)( thr, lock );
florian6bf37262012-10-21 03:23:36 +00001271 tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetA, (UWord)lock ));
1272 tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetW, (UWord)lock ));
sewardjb4112022007-11-09 22:49:28 +00001273 goto error;
1274 }
1275
sewardjf98e1c02008-10-25 16:22:41 +00001276 /* test just above dominates */
1277 tl_assert(lock->heldBy);
1278 was_heldW = lock->heldW;
1279
sewardjb4112022007-11-09 22:49:28 +00001280 /* The lock is held. Is this thread one of the holders? If not,
1281 report a bug in the client. */
florian6bf37262012-10-21 03:23:36 +00001282 n = VG_(elemBag)( lock->heldBy, (UWord)thr );
sewardjb4112022007-11-09 22:49:28 +00001283 tl_assert(n >= 0);
1284 if (n == 0) {
1285 /* We are not a current holder of the lock. This is a bug in
1286 the guest, and (per POSIX pthread rules) the unlock
1287 attempt will fail. So just complain and do nothing
1288 else. */
sewardj896f6f92008-08-19 08:38:52 +00001289 Thread* realOwner = (Thread*)VG_(anyElementOfBag)( lock->heldBy );
sewardjf98e1c02008-10-25 16:22:41 +00001290 tl_assert(HG_(is_sane_Thread)(realOwner));
sewardjb4112022007-11-09 22:49:28 +00001291 tl_assert(realOwner != thr);
florian6bf37262012-10-21 03:23:36 +00001292 tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetA, (UWord)lock ));
1293 tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetW, (UWord)lock ));
sewardjf98e1c02008-10-25 16:22:41 +00001294 HG_(record_error_UnlockForeign)( thr, realOwner, lock );
sewardjb4112022007-11-09 22:49:28 +00001295 goto error;
1296 }
1297
1298 /* Ok, we hold the lock 'n' times. */
1299 tl_assert(n >= 1);
1300
1301 lockN_release( lock, thr );
1302
1303 n--;
1304 tl_assert(n >= 0);
1305
1306 if (n > 0) {
1307 tl_assert(lock->heldBy);
florian6bf37262012-10-21 03:23:36 +00001308 tl_assert(n == VG_(elemBag)( lock->heldBy, (UWord)thr ));
sewardjb4112022007-11-09 22:49:28 +00001309 /* We still hold the lock. So either it's a recursive lock
1310 or a rwlock which is currently r-held. */
1311 tl_assert(lock->kind == LK_mbRec
1312 || (lock->kind == LK_rdwr && !lock->heldW));
florian6bf37262012-10-21 03:23:36 +00001313 tl_assert(HG_(elemWS)( univ_lsets, thr->locksetA, (UWord)lock ));
sewardjb4112022007-11-09 22:49:28 +00001314 if (lock->heldW)
florian6bf37262012-10-21 03:23:36 +00001315 tl_assert(HG_(elemWS)( univ_lsets, thr->locksetW, (UWord)lock ));
sewardjb4112022007-11-09 22:49:28 +00001316 else
florian6bf37262012-10-21 03:23:36 +00001317 tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetW, (UWord)lock ));
sewardjb4112022007-11-09 22:49:28 +00001318 } else {
sewardj983f3022009-05-21 14:49:55 +00001319 /* n is zero. This means we don't hold the lock any more. But
1320 if it's a rwlock held in r-mode, someone else could still
1321 hold it. Just do whatever sanity checks we can. */
1322 if (lock->kind == LK_rdwr && lock->heldBy) {
1323 /* It's a rwlock. We no longer hold it but we used to;
1324 nevertheless it still appears to be held by someone else.
1325 The implication is that, prior to this release, it must
1326 have been shared by us and and whoever else is holding it;
1327 which in turn implies it must be r-held, since a lock
1328 can't be w-held by more than one thread. */
1329 /* The lock is now R-held by somebody else: */
1330 tl_assert(lock->heldW == False);
1331 } else {
1332 /* Normal case. It's either not a rwlock, or it's a rwlock
1333 that we used to hold in w-mode (which is pretty much the
1334 same thing as a non-rwlock.) Since this transaction is
1335 atomic (V does not allow multiple threads to run
1336 simultaneously), it must mean the lock is now not held by
1337 anybody. Hence assert for it. */
1338 /* The lock is now not held by anybody: */
1339 tl_assert(!lock->heldBy);
1340 tl_assert(lock->heldW == False);
1341 }
sewardjf98e1c02008-10-25 16:22:41 +00001342 //if (lock->heldBy) {
florian6bf37262012-10-21 03:23:36 +00001343 // tl_assert(0 == VG_(elemBag)( lock->heldBy, (UWord)thr ));
sewardjf98e1c02008-10-25 16:22:41 +00001344 //}
sewardjb4112022007-11-09 22:49:28 +00001345 /* update this thread's lockset accordingly. */
1346 thr->locksetA
florian6bf37262012-10-21 03:23:36 +00001347 = HG_(delFromWS)( univ_lsets, thr->locksetA, (UWord)lock );
sewardjb4112022007-11-09 22:49:28 +00001348 thr->locksetW
florian6bf37262012-10-21 03:23:36 +00001349 = HG_(delFromWS)( univ_lsets, thr->locksetW, (UWord)lock );
sewardjf98e1c02008-10-25 16:22:41 +00001350 /* push our VC into the lock */
1351 tl_assert(thr->hbthr);
1352 tl_assert(lock->hbso);
1353 /* If the lock was previously W-held, then we want to do a
1354 strong send, and if previously R-held, then a weak send. */
1355 libhb_so_send( thr->hbthr, lock->hbso, was_heldW );
sewardjb4112022007-11-09 22:49:28 +00001356 }
1357 /* fall through */
1358
1359 error:
sewardjf98e1c02008-10-25 16:22:41 +00001360 tl_assert(HG_(is_sane_LockN)(lock));
sewardjb4112022007-11-09 22:49:28 +00001361}
1362
1363
sewardj9f569b72008-11-13 13:33:09 +00001364/* ---------------------------------------------------------- */
1365/* -------- Event handlers proper (evh__* functions) -------- */
1366/* ---------------------------------------------------------- */
sewardjb4112022007-11-09 22:49:28 +00001367
1368/* What is the Thread* for the currently running thread? This is
1369 absolutely performance critical. We receive notifications from the
1370 core for client code starts/stops, and cache the looked-up result
1371 in 'current_Thread'. Hence, for the vast majority of requests,
1372 finding the current thread reduces to a read of a global variable,
1373 provided get_current_Thread_in_C_C is inlined.
1374
1375 Outside of client code, current_Thread is NULL, and presumably
1376 any uses of it will cause a segfault. Hence:
1377
1378 - for uses definitely within client code, use
1379 get_current_Thread_in_C_C.
1380
1381 - for all other uses, use get_current_Thread.
1382*/
1383
sewardj23f12002009-07-24 08:45:08 +00001384static Thread *current_Thread = NULL,
1385 *current_Thread_prev = NULL;
sewardjb4112022007-11-09 22:49:28 +00001386
1387static void evh__start_client_code ( ThreadId tid, ULong nDisp ) {
1388 if (0) VG_(printf)("start %d %llu\n", (Int)tid, nDisp);
1389 tl_assert(current_Thread == NULL);
1390 current_Thread = map_threads_lookup( tid );
1391 tl_assert(current_Thread != NULL);
sewardj23f12002009-07-24 08:45:08 +00001392 if (current_Thread != current_Thread_prev) {
1393 libhb_Thr_resumes( current_Thread->hbthr );
1394 current_Thread_prev = current_Thread;
1395 }
sewardjb4112022007-11-09 22:49:28 +00001396}
1397static void evh__stop_client_code ( ThreadId tid, ULong nDisp ) {
1398 if (0) VG_(printf)(" stop %d %llu\n", (Int)tid, nDisp);
1399 tl_assert(current_Thread != NULL);
1400 current_Thread = NULL;
sewardjf98e1c02008-10-25 16:22:41 +00001401 libhb_maybe_GC();
sewardjb4112022007-11-09 22:49:28 +00001402}
1403static inline Thread* get_current_Thread_in_C_C ( void ) {
1404 return current_Thread;
1405}
1406static inline Thread* get_current_Thread ( void ) {
1407 ThreadId coretid;
1408 Thread* thr;
1409 thr = get_current_Thread_in_C_C();
1410 if (LIKELY(thr))
1411 return thr;
1412 /* evidently not in client code. Do it the slow way. */
1413 coretid = VG_(get_running_tid)();
1414 /* FIXME: get rid of the following kludge. It exists because
sewardjf98e1c02008-10-25 16:22:41 +00001415 evh__new_mem is called during initialisation (as notification
sewardjb4112022007-11-09 22:49:28 +00001416 of initial memory layout) and VG_(get_running_tid)() returns
1417 VG_INVALID_THREADID at that point. */
1418 if (coretid == VG_INVALID_THREADID)
1419 coretid = 1; /* KLUDGE */
1420 thr = map_threads_lookup( coretid );
1421 return thr;
1422}
1423
1424static
1425void evh__new_mem ( Addr a, SizeT len ) {
1426 if (SHOW_EVENTS >= 2)
1427 VG_(printf)("evh__new_mem(%p, %lu)\n", (void*)a, len );
1428 shadow_mem_make_New( get_current_Thread(), a, len );
sewardjf98e1c02008-10-25 16:22:41 +00001429 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
sewardjb4112022007-11-09 22:49:28 +00001430 all__sanity_check("evh__new_mem-post");
1431}
1432
1433static
sewardj1f77fec2010-04-12 19:51:04 +00001434void evh__new_mem_stack ( Addr a, SizeT len ) {
1435 if (SHOW_EVENTS >= 2)
1436 VG_(printf)("evh__new_mem_stack(%p, %lu)\n", (void*)a, len );
1437 shadow_mem_make_New( get_current_Thread(),
1438 -VG_STACK_REDZONE_SZB + a, len );
1439 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1440 all__sanity_check("evh__new_mem_stack-post");
1441}
1442
1443static
sewardj7cf4e6b2008-05-01 20:24:26 +00001444void evh__new_mem_w_tid ( Addr a, SizeT len, ThreadId tid ) {
1445 if (SHOW_EVENTS >= 2)
1446 VG_(printf)("evh__new_mem_w_tid(%p, %lu)\n", (void*)a, len );
1447 shadow_mem_make_New( get_current_Thread(), a, len );
sewardjf98e1c02008-10-25 16:22:41 +00001448 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
sewardj7cf4e6b2008-05-01 20:24:26 +00001449 all__sanity_check("evh__new_mem_w_tid-post");
1450}
1451
1452static
sewardjb4112022007-11-09 22:49:28 +00001453void evh__new_mem_w_perms ( Addr a, SizeT len,
sewardj9c606bd2008-09-18 18:12:50 +00001454 Bool rr, Bool ww, Bool xx, ULong di_handle ) {
sewardjb4112022007-11-09 22:49:28 +00001455 if (SHOW_EVENTS >= 1)
1456 VG_(printf)("evh__new_mem_w_perms(%p, %lu, %d,%d,%d)\n",
1457 (void*)a, len, (Int)rr, (Int)ww, (Int)xx );
1458 if (rr || ww || xx)
1459 shadow_mem_make_New( get_current_Thread(), a, len );
sewardjf98e1c02008-10-25 16:22:41 +00001460 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
sewardjb4112022007-11-09 22:49:28 +00001461 all__sanity_check("evh__new_mem_w_perms-post");
1462}
1463
1464static
1465void evh__set_perms ( Addr a, SizeT len,
1466 Bool rr, Bool ww, Bool xx ) {
sewardjfd35d492011-03-17 19:39:55 +00001467 // This handles mprotect requests. If the memory is being put
1468 // into no-R no-W state, paint it as NoAccess, for the reasons
1469 // documented at evh__die_mem_munmap().
sewardjb4112022007-11-09 22:49:28 +00001470 if (SHOW_EVENTS >= 1)
sewardjfd35d492011-03-17 19:39:55 +00001471 VG_(printf)("evh__set_perms(%p, %lu, r=%d w=%d x=%d)\n",
sewardjb4112022007-11-09 22:49:28 +00001472 (void*)a, len, (Int)rr, (Int)ww, (Int)xx );
1473 /* Hmm. What should we do here, that actually makes any sense?
1474 Let's say: if neither readable nor writable, then declare it
1475 NoAccess, else leave it alone. */
1476 if (!(rr || ww))
sewardjfd35d492011-03-17 19:39:55 +00001477 shadow_mem_make_NoAccess_AHAE( get_current_Thread(), a, len );
sewardjf98e1c02008-10-25 16:22:41 +00001478 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
sewardjb4112022007-11-09 22:49:28 +00001479 all__sanity_check("evh__set_perms-post");
1480}
1481
1482static
1483void evh__die_mem ( Addr a, SizeT len ) {
sewardjfd35d492011-03-17 19:39:55 +00001484 // Urr, libhb ignores this.
sewardjb4112022007-11-09 22:49:28 +00001485 if (SHOW_EVENTS >= 2)
1486 VG_(printf)("evh__die_mem(%p, %lu)\n", (void*)a, len );
sewardjfd35d492011-03-17 19:39:55 +00001487 shadow_mem_make_NoAccess_NoFX( get_current_Thread(), a, len );
sewardjf98e1c02008-10-25 16:22:41 +00001488 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
sewardjb4112022007-11-09 22:49:28 +00001489 all__sanity_check("evh__die_mem-post");
1490}
1491
1492static
sewardjfd35d492011-03-17 19:39:55 +00001493void evh__die_mem_munmap ( Addr a, SizeT len ) {
1494 // It's important that libhb doesn't ignore this. If, as is likely,
1495 // the client is subject to address space layout randomization,
1496 // then unmapped areas may never get remapped over, even in long
1497 // runs. If we just ignore them we wind up with large resource
1498 // (VTS) leaks in libhb. So force them to NoAccess, so that all
1499 // VTS references in the affected area are dropped. Marking memory
1500 // as NoAccess is expensive, but we assume that munmap is sufficiently
1501 // rare that the space gains of doing this are worth the costs.
1502 if (SHOW_EVENTS >= 2)
1503 VG_(printf)("evh__die_mem_munmap(%p, %lu)\n", (void*)a, len );
1504 shadow_mem_make_NoAccess_AHAE( get_current_Thread(), a, len );
1505}
1506
1507static
sewardj406bac82010-03-03 23:03:40 +00001508void evh__untrack_mem ( Addr a, SizeT len ) {
sewardjfd35d492011-03-17 19:39:55 +00001509 // Libhb doesn't ignore this.
sewardj406bac82010-03-03 23:03:40 +00001510 if (SHOW_EVENTS >= 2)
1511 VG_(printf)("evh__untrack_mem(%p, %lu)\n", (void*)a, len );
1512 shadow_mem_make_Untracked( get_current_Thread(), a, len );
1513 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1514 all__sanity_check("evh__untrack_mem-post");
1515}
1516
1517static
sewardj23f12002009-07-24 08:45:08 +00001518void evh__copy_mem ( Addr src, Addr dst, SizeT len ) {
1519 if (SHOW_EVENTS >= 2)
1520 VG_(printf)("evh__copy_mem(%p, %p, %lu)\n", (void*)src, (void*)dst, len );
1521 shadow_mem_scopy_range( get_current_Thread(), src, dst, len );
1522 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1523 all__sanity_check("evh__copy_mem-post");
1524}
1525
1526static
sewardjb4112022007-11-09 22:49:28 +00001527void evh__pre_thread_ll_create ( ThreadId parent, ThreadId child )
1528{
1529 if (SHOW_EVENTS >= 1)
1530 VG_(printf)("evh__pre_thread_ll_create(p=%d, c=%d)\n",
1531 (Int)parent, (Int)child );
1532
1533 if (parent != VG_INVALID_THREADID) {
sewardjf98e1c02008-10-25 16:22:41 +00001534 Thread* thr_p;
1535 Thread* thr_c;
1536 Thr* hbthr_p;
1537 Thr* hbthr_c;
sewardjb4112022007-11-09 22:49:28 +00001538
sewardjf98e1c02008-10-25 16:22:41 +00001539 tl_assert(HG_(is_sane_ThreadId)(parent));
1540 tl_assert(HG_(is_sane_ThreadId)(child));
sewardjb4112022007-11-09 22:49:28 +00001541 tl_assert(parent != child);
1542
1543 thr_p = map_threads_maybe_lookup( parent );
1544 thr_c = map_threads_maybe_lookup( child );
1545
1546 tl_assert(thr_p != NULL);
1547 tl_assert(thr_c == NULL);
1548
sewardjf98e1c02008-10-25 16:22:41 +00001549 hbthr_p = thr_p->hbthr;
1550 tl_assert(hbthr_p != NULL);
sewardj60626642011-03-10 15:14:37 +00001551 tl_assert( libhb_get_Thr_hgthread(hbthr_p) == thr_p );
sewardjb4112022007-11-09 22:49:28 +00001552
sewardjf98e1c02008-10-25 16:22:41 +00001553 hbthr_c = libhb_create ( hbthr_p );
1554
1555 /* Create a new thread record for the child. */
sewardjb4112022007-11-09 22:49:28 +00001556 /* a Thread for the new thread ... */
sewardjf98e1c02008-10-25 16:22:41 +00001557 thr_c = mk_Thread( hbthr_c );
sewardj60626642011-03-10 15:14:37 +00001558 tl_assert( libhb_get_Thr_hgthread(hbthr_c) == NULL );
1559 libhb_set_Thr_hgthread(hbthr_c, thr_c);
sewardjb4112022007-11-09 22:49:28 +00001560
1561 /* and bind it in the thread-map table */
1562 map_threads[child] = thr_c;
sewardjf98e1c02008-10-25 16:22:41 +00001563 tl_assert(thr_c->coretid == VG_INVALID_THREADID);
1564 thr_c->coretid = child;
sewardjb4112022007-11-09 22:49:28 +00001565
1566 /* Record where the parent is so we can later refer to this in
1567 error messages.
1568
mjw36750c02014-08-30 20:37:40 +00001569 On x86/amd64-linux, this entails a nasty glibc specific hack.
sewardjb4112022007-11-09 22:49:28 +00001570 The stack snapshot is taken immediately after the parent has
1571 returned from its sys_clone call. Unfortunately there is no
1572 unwind info for the insn following "syscall" - reading the
1573 glibc sources confirms this. So we ask for a snapshot to be
1574 taken as if RIP was 3 bytes earlier, in a place where there
1575 is unwind info. Sigh.
1576 */
1577 { Word first_ip_delta = 0;
mjw36750c02014-08-30 20:37:40 +00001578# if defined(VGP_amd64_linux) || defined(VGP_x86_linux)
sewardjb4112022007-11-09 22:49:28 +00001579 first_ip_delta = -3;
mjw4fa71082014-09-01 15:29:55 +00001580# elif defined(VGP_arm64_linux) || defined(VGP_arm_linux)
sewardj5a460f52014-08-30 19:24:05 +00001581 first_ip_delta = -1;
sewardjb4112022007-11-09 22:49:28 +00001582# endif
1583 thr_c->created_at = VG_(record_ExeContext)(parent, first_ip_delta);
1584 }
sewardjb4112022007-11-09 22:49:28 +00001585 }
1586
sewardjf98e1c02008-10-25 16:22:41 +00001587 if (HG_(clo_sanity_flags) & SCE_THREADS)
sewardjb4112022007-11-09 22:49:28 +00001588 all__sanity_check("evh__pre_thread_create-post");
1589}
1590
1591static
1592void evh__pre_thread_ll_exit ( ThreadId quit_tid )
1593{
1594 Int nHeld;
1595 Thread* thr_q;
1596 if (SHOW_EVENTS >= 1)
1597 VG_(printf)("evh__pre_thread_ll_exit(thr=%d)\n",
1598 (Int)quit_tid );
1599
1600 /* quit_tid has disappeared without joining to any other thread.
1601 Therefore there is no synchronisation event associated with its
1602 exit and so we have to pretty much treat it as if it was still
1603 alive but mysteriously making no progress. That is because, if
1604 we don't know when it really exited, then we can never say there
1605 is a point in time when we're sure the thread really has
1606 finished, and so we need to consider the possibility that it
1607 lingers indefinitely and continues to interact with other
1608 threads. */
1609 /* However, it might have rendezvous'd with a thread that called
1610 pthread_join with this one as arg, prior to this point (that's
1611 how NPTL works). In which case there has already been a prior
1612 sync event. So in any case, just let the thread exit. On NPTL,
1613 all thread exits go through here. */
sewardjf98e1c02008-10-25 16:22:41 +00001614 tl_assert(HG_(is_sane_ThreadId)(quit_tid));
sewardjb4112022007-11-09 22:49:28 +00001615 thr_q = map_threads_maybe_lookup( quit_tid );
1616 tl_assert(thr_q != NULL);
1617
1618 /* Complain if this thread holds any locks. */
1619 nHeld = HG_(cardinalityWS)( univ_lsets, thr_q->locksetA );
1620 tl_assert(nHeld >= 0);
1621 if (nHeld > 0) {
1622 HChar buf[80];
1623 VG_(sprintf)(buf, "Exiting thread still holds %d lock%s",
1624 nHeld, nHeld > 1 ? "s" : "");
sewardjf98e1c02008-10-25 16:22:41 +00001625 HG_(record_error_Misc)( thr_q, buf );
sewardjb4112022007-11-09 22:49:28 +00001626 }
1627
sewardj23f12002009-07-24 08:45:08 +00001628 /* Not much to do here:
1629 - tell libhb the thread is gone
1630 - clear the map_threads entry, in order that the Valgrind core
1631 can re-use it. */
sewardj61bc2c52011-02-09 10:34:00 +00001632 /* Cleanup actions (next 5 lines) copied in evh__atfork_child; keep
1633 in sync. */
sewardj23f12002009-07-24 08:45:08 +00001634 tl_assert(thr_q->hbthr);
1635 libhb_async_exit(thr_q->hbthr);
sewardjf98e1c02008-10-25 16:22:41 +00001636 tl_assert(thr_q->coretid == quit_tid);
1637 thr_q->coretid = VG_INVALID_THREADID;
sewardjb4112022007-11-09 22:49:28 +00001638 map_threads_delete( quit_tid );
1639
sewardjf98e1c02008-10-25 16:22:41 +00001640 if (HG_(clo_sanity_flags) & SCE_THREADS)
sewardjb4112022007-11-09 22:49:28 +00001641 all__sanity_check("evh__pre_thread_ll_exit-post");
1642}
1643
sewardj61bc2c52011-02-09 10:34:00 +00001644/* This is called immediately after fork, for the child only. 'tid'
1645 is the only surviving thread (as per POSIX rules on fork() in
1646 threaded programs), so we have to clean up map_threads to remove
1647 entries for any other threads. */
1648static
1649void evh__atfork_child ( ThreadId tid )
1650{
1651 UInt i;
1652 Thread* thr;
1653 /* Slot 0 should never be used. */
1654 thr = map_threads_maybe_lookup( 0/*INVALID*/ );
1655 tl_assert(!thr);
1656 /* Clean up all other slots except 'tid'. */
1657 for (i = 1; i < VG_N_THREADS; i++) {
1658 if (i == tid)
1659 continue;
1660 thr = map_threads_maybe_lookup(i);
1661 if (!thr)
1662 continue;
1663 /* Cleanup actions (next 5 lines) copied from end of
1664 evh__pre_thread_ll_exit; keep in sync. */
1665 tl_assert(thr->hbthr);
1666 libhb_async_exit(thr->hbthr);
1667 tl_assert(thr->coretid == i);
1668 thr->coretid = VG_INVALID_THREADID;
1669 map_threads_delete(i);
1670 }
1671}
1672
philipped40aff52014-06-16 20:00:14 +00001673/* generate a dependence from the hbthr_q quitter to the hbthr_s stayer. */
sewardjb4112022007-11-09 22:49:28 +00001674static
philipped40aff52014-06-16 20:00:14 +00001675void generate_quitter_stayer_dependence (Thr* hbthr_q, Thr* hbthr_s)
sewardjb4112022007-11-09 22:49:28 +00001676{
sewardjf98e1c02008-10-25 16:22:41 +00001677 SO* so;
sewardjf98e1c02008-10-25 16:22:41 +00001678 /* Allocate a temporary synchronisation object and use it to send
1679 an imaginary message from the quitter to the stayer, the purpose
1680 being to generate a dependence from the quitter to the
1681 stayer. */
1682 so = libhb_so_alloc();
1683 tl_assert(so);
sewardj23f12002009-07-24 08:45:08 +00001684 /* Send last arg of _so_send as False, since the sending thread
1685 doesn't actually exist any more, so we don't want _so_send to
1686 try taking stack snapshots of it. */
sewardjffce8152011-06-24 10:09:41 +00001687 libhb_so_send(hbthr_q, so, True/*strong_send*//*?!? wrt comment above*/);
sewardjf98e1c02008-10-25 16:22:41 +00001688 libhb_so_recv(hbthr_s, so, True/*strong_recv*/);
1689 libhb_so_dealloc(so);
sewardjb4112022007-11-09 22:49:28 +00001690
sewardjffce8152011-06-24 10:09:41 +00001691 /* Tell libhb that the quitter has been reaped. Note that we might
1692 have to be cleverer about this, to exclude 2nd and subsequent
1693 notifications for the same hbthr_q, in the case where the app is
1694 buggy (calls pthread_join twice or more on the same thread) AND
1695 where libpthread is also buggy and doesn't return ESRCH on
1696 subsequent calls. (If libpthread isn't thusly buggy, then the
1697 wrapper for pthread_join in hg_intercepts.c will stop us getting
1698 notified here multiple times for the same joinee.) See also
1699 comments in helgrind/tests/jointwice.c. */
1700 libhb_joinedwith_done(hbthr_q);
philipped40aff52014-06-16 20:00:14 +00001701}
1702
1703
1704static
1705void evh__HG_PTHREAD_JOIN_POST ( ThreadId stay_tid, Thread* quit_thr )
1706{
1707 Thread* thr_s;
1708 Thread* thr_q;
1709 Thr* hbthr_s;
1710 Thr* hbthr_q;
1711
1712 if (SHOW_EVENTS >= 1)
1713 VG_(printf)("evh__post_thread_join(stayer=%d, quitter=%p)\n",
1714 (Int)stay_tid, quit_thr );
1715
1716 tl_assert(HG_(is_sane_ThreadId)(stay_tid));
1717
1718 thr_s = map_threads_maybe_lookup( stay_tid );
1719 thr_q = quit_thr;
1720 tl_assert(thr_s != NULL);
1721 tl_assert(thr_q != NULL);
1722 tl_assert(thr_s != thr_q);
1723
1724 hbthr_s = thr_s->hbthr;
1725 hbthr_q = thr_q->hbthr;
1726 tl_assert(hbthr_s != hbthr_q);
1727 tl_assert( libhb_get_Thr_hgthread(hbthr_s) == thr_s );
1728 tl_assert( libhb_get_Thr_hgthread(hbthr_q) == thr_q );
1729
1730 generate_quitter_stayer_dependence (hbthr_q, hbthr_s);
sewardjffce8152011-06-24 10:09:41 +00001731
sewardjf98e1c02008-10-25 16:22:41 +00001732 /* evh__pre_thread_ll_exit issues an error message if the exiting
1733 thread holds any locks. No need to check here. */
sewardjb4112022007-11-09 22:49:28 +00001734
1735 /* This holds because, at least when using NPTL as the thread
1736 library, we should be notified the low level thread exit before
1737 we hear of any join event on it. The low level exit
1738 notification feeds through into evh__pre_thread_ll_exit,
1739 which should clear the map_threads entry for it. Hence we
1740 expect there to be no map_threads entry at this point. */
1741 tl_assert( map_threads_maybe_reverse_lookup_SLOW(thr_q)
1742 == VG_INVALID_THREADID);
1743
sewardjf98e1c02008-10-25 16:22:41 +00001744 if (HG_(clo_sanity_flags) & SCE_THREADS)
sewardjb4112022007-11-09 22:49:28 +00001745 all__sanity_check("evh__post_thread_join-post");
1746}
1747
1748static
floriane543f302012-10-21 19:43:43 +00001749void evh__pre_mem_read ( CorePart part, ThreadId tid, const HChar* s,
sewardjb4112022007-11-09 22:49:28 +00001750 Addr a, SizeT size) {
1751 if (SHOW_EVENTS >= 2
1752 || (SHOW_EVENTS >= 1 && size != 1))
1753 VG_(printf)("evh__pre_mem_read(ctid=%d, \"%s\", %p, %lu)\n",
1754 (Int)tid, s, (void*)a, size );
sewardj23f12002009-07-24 08:45:08 +00001755 shadow_mem_cread_range( map_threads_lookup(tid), a, size);
sewardjf98e1c02008-10-25 16:22:41 +00001756 if (size >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
sewardjb4112022007-11-09 22:49:28 +00001757 all__sanity_check("evh__pre_mem_read-post");
1758}
1759
1760static
1761void evh__pre_mem_read_asciiz ( CorePart part, ThreadId tid,
floriane543f302012-10-21 19:43:43 +00001762 const HChar* s, Addr a ) {
sewardjb4112022007-11-09 22:49:28 +00001763 Int len;
1764 if (SHOW_EVENTS >= 1)
1765 VG_(printf)("evh__pre_mem_asciiz(ctid=%d, \"%s\", %p)\n",
1766 (Int)tid, s, (void*)a );
sewardj234e5582011-02-09 12:47:23 +00001767 // Don't segfault if the string starts in an obviously stupid
1768 // place. Actually we should check the whole string, not just
1769 // the start address, but that's too much trouble. At least
1770 // checking the first byte is better than nothing. See #255009.
1771 if (!VG_(am_is_valid_for_client) (a, 1, VKI_PROT_READ))
1772 return;
florian19f91bb2012-11-10 22:29:54 +00001773 len = VG_(strlen)( (HChar*) a );
sewardj23f12002009-07-24 08:45:08 +00001774 shadow_mem_cread_range( map_threads_lookup(tid), a, len+1 );
sewardjf98e1c02008-10-25 16:22:41 +00001775 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
sewardjb4112022007-11-09 22:49:28 +00001776 all__sanity_check("evh__pre_mem_read_asciiz-post");
1777}
1778
1779static
floriane543f302012-10-21 19:43:43 +00001780void evh__pre_mem_write ( CorePart part, ThreadId tid, const HChar* s,
sewardjb4112022007-11-09 22:49:28 +00001781 Addr a, SizeT size ) {
1782 if (SHOW_EVENTS >= 1)
1783 VG_(printf)("evh__pre_mem_write(ctid=%d, \"%s\", %p, %lu)\n",
1784 (Int)tid, s, (void*)a, size );
sewardj23f12002009-07-24 08:45:08 +00001785 shadow_mem_cwrite_range( map_threads_lookup(tid), a, size);
sewardjf98e1c02008-10-25 16:22:41 +00001786 if (size >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
sewardjb4112022007-11-09 22:49:28 +00001787 all__sanity_check("evh__pre_mem_write-post");
1788}
1789
1790static
1791void evh__new_mem_heap ( Addr a, SizeT len, Bool is_inited ) {
1792 if (SHOW_EVENTS >= 1)
1793 VG_(printf)("evh__new_mem_heap(%p, %lu, inited=%d)\n",
1794 (void*)a, len, (Int)is_inited );
sewardj438c4712014-09-05 20:29:10 +00001795 // We ignore the initialisation state (is_inited); that's ok.
1796 shadow_mem_make_New(get_current_Thread(), a, len);
sewardjf98e1c02008-10-25 16:22:41 +00001797 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
sewardjb4112022007-11-09 22:49:28 +00001798 all__sanity_check("evh__pre_mem_read-post");
1799}
1800
1801static
1802void evh__die_mem_heap ( Addr a, SizeT len ) {
sewardj622fe492011-03-11 21:06:59 +00001803 Thread* thr;
sewardjb4112022007-11-09 22:49:28 +00001804 if (SHOW_EVENTS >= 1)
1805 VG_(printf)("evh__die_mem_heap(%p, %lu)\n", (void*)a, len );
sewardj622fe492011-03-11 21:06:59 +00001806 thr = get_current_Thread();
1807 tl_assert(thr);
1808 if (HG_(clo_free_is_write)) {
1809 /* Treat frees as if the memory was written immediately prior to
1810 the free. This shakes out more races, specifically, cases
1811 where memory is referenced by one thread, and freed by
1812 another, and there's no observable synchronisation event to
1813 guarantee that the reference happens before the free. */
1814 shadow_mem_cwrite_range(thr, a, len);
1815 }
philippef54cb662015-05-10 22:19:31 +00001816 shadow_mem_make_NoAccess_AHAE( thr, a, len );
1817 /* We used to call instead
1818 shadow_mem_make_NoAccess_NoFX( thr, a, len );
1819 A non-buggy application will not access anymore
1820 the freed memory, and so marking no access is in theory useless.
1821 Not marking freed memory would avoid the overhead for applications
1822 doing mostly malloc/free, as the freed memory should then be recycled
1823 very quickly after marking.
1824 We rather mark it noaccess for the following reasons:
1825 * accessibility bits then always correctly represents the memory
1826 status (e.g. for the client request VALGRIND_HG_GET_ABITS).
1827 * the overhead is reasonable (about 5 seconds per Gb in 1000 bytes
1828 blocks, on a ppc64le, for a unrealistic workload of an application
1829 doing only malloc/free).
1830 * marking no access allows to GC the SecMap, which might improve
1831 performance and/or memory usage.
1832 * we might detect more applications bugs when memory is marked
1833 noaccess.
1834 If needed, we could support here an option --free-is-noaccess=yes|no
1835 to avoid marking freed memory as no access if some applications
1836 would need to avoid the marking noaccess overhead. */
1837
sewardjf98e1c02008-10-25 16:22:41 +00001838 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
sewardjb4112022007-11-09 22:49:28 +00001839 all__sanity_check("evh__pre_mem_read-post");
1840}
1841
sewardj23f12002009-07-24 08:45:08 +00001842/* --- Event handlers called from generated code --- */
1843
sewardjb4112022007-11-09 22:49:28 +00001844static VG_REGPARM(1)
sewardj23f12002009-07-24 08:45:08 +00001845void evh__mem_help_cread_1(Addr a) {
sewardjf98e1c02008-10-25 16:22:41 +00001846 Thread* thr = get_current_Thread_in_C_C();
1847 Thr* hbthr = thr->hbthr;
sewardj23f12002009-07-24 08:45:08 +00001848 LIBHB_CREAD_1(hbthr, a);
sewardjb4112022007-11-09 22:49:28 +00001849}
sewardjf98e1c02008-10-25 16:22:41 +00001850
sewardjb4112022007-11-09 22:49:28 +00001851static VG_REGPARM(1)
sewardj23f12002009-07-24 08:45:08 +00001852void evh__mem_help_cread_2(Addr a) {
sewardjf98e1c02008-10-25 16:22:41 +00001853 Thread* thr = get_current_Thread_in_C_C();
1854 Thr* hbthr = thr->hbthr;
sewardj23f12002009-07-24 08:45:08 +00001855 LIBHB_CREAD_2(hbthr, a);
sewardjb4112022007-11-09 22:49:28 +00001856}
sewardjf98e1c02008-10-25 16:22:41 +00001857
sewardjb4112022007-11-09 22:49:28 +00001858static VG_REGPARM(1)
sewardj23f12002009-07-24 08:45:08 +00001859void evh__mem_help_cread_4(Addr a) {
sewardjf98e1c02008-10-25 16:22:41 +00001860 Thread* thr = get_current_Thread_in_C_C();
1861 Thr* hbthr = thr->hbthr;
sewardj23f12002009-07-24 08:45:08 +00001862 LIBHB_CREAD_4(hbthr, a);
sewardjb4112022007-11-09 22:49:28 +00001863}
sewardjf98e1c02008-10-25 16:22:41 +00001864
sewardjb4112022007-11-09 22:49:28 +00001865static VG_REGPARM(1)
sewardj23f12002009-07-24 08:45:08 +00001866void evh__mem_help_cread_8(Addr a) {
sewardjf98e1c02008-10-25 16:22:41 +00001867 Thread* thr = get_current_Thread_in_C_C();
1868 Thr* hbthr = thr->hbthr;
sewardj23f12002009-07-24 08:45:08 +00001869 LIBHB_CREAD_8(hbthr, a);
sewardjb4112022007-11-09 22:49:28 +00001870}
sewardjf98e1c02008-10-25 16:22:41 +00001871
sewardjb4112022007-11-09 22:49:28 +00001872static VG_REGPARM(2)
sewardj23f12002009-07-24 08:45:08 +00001873void evh__mem_help_cread_N(Addr a, SizeT size) {
sewardjf98e1c02008-10-25 16:22:41 +00001874 Thread* thr = get_current_Thread_in_C_C();
1875 Thr* hbthr = thr->hbthr;
sewardj23f12002009-07-24 08:45:08 +00001876 LIBHB_CREAD_N(hbthr, a, size);
sewardjb4112022007-11-09 22:49:28 +00001877}
1878
1879static VG_REGPARM(1)
sewardj23f12002009-07-24 08:45:08 +00001880void evh__mem_help_cwrite_1(Addr a) {
sewardjf98e1c02008-10-25 16:22:41 +00001881 Thread* thr = get_current_Thread_in_C_C();
1882 Thr* hbthr = thr->hbthr;
sewardj23f12002009-07-24 08:45:08 +00001883 LIBHB_CWRITE_1(hbthr, a);
sewardjb4112022007-11-09 22:49:28 +00001884}
sewardjf98e1c02008-10-25 16:22:41 +00001885
sewardjb4112022007-11-09 22:49:28 +00001886static VG_REGPARM(1)
sewardj23f12002009-07-24 08:45:08 +00001887void evh__mem_help_cwrite_2(Addr a) {
sewardjf98e1c02008-10-25 16:22:41 +00001888 Thread* thr = get_current_Thread_in_C_C();
1889 Thr* hbthr = thr->hbthr;
sewardj23f12002009-07-24 08:45:08 +00001890 LIBHB_CWRITE_2(hbthr, a);
sewardjb4112022007-11-09 22:49:28 +00001891}
sewardjf98e1c02008-10-25 16:22:41 +00001892
sewardjb4112022007-11-09 22:49:28 +00001893static VG_REGPARM(1)
sewardj23f12002009-07-24 08:45:08 +00001894void evh__mem_help_cwrite_4(Addr a) {
sewardjf98e1c02008-10-25 16:22:41 +00001895 Thread* thr = get_current_Thread_in_C_C();
1896 Thr* hbthr = thr->hbthr;
sewardj23f12002009-07-24 08:45:08 +00001897 LIBHB_CWRITE_4(hbthr, a);
sewardjb4112022007-11-09 22:49:28 +00001898}
sewardjf98e1c02008-10-25 16:22:41 +00001899
sewardjb4112022007-11-09 22:49:28 +00001900static VG_REGPARM(1)
sewardj23f12002009-07-24 08:45:08 +00001901void evh__mem_help_cwrite_8(Addr a) {
sewardjf98e1c02008-10-25 16:22:41 +00001902 Thread* thr = get_current_Thread_in_C_C();
1903 Thr* hbthr = thr->hbthr;
sewardj23f12002009-07-24 08:45:08 +00001904 LIBHB_CWRITE_8(hbthr, a);
sewardjb4112022007-11-09 22:49:28 +00001905}
sewardjf98e1c02008-10-25 16:22:41 +00001906
sewardjb4112022007-11-09 22:49:28 +00001907static VG_REGPARM(2)
sewardj23f12002009-07-24 08:45:08 +00001908void evh__mem_help_cwrite_N(Addr a, SizeT size) {
sewardjf98e1c02008-10-25 16:22:41 +00001909 Thread* thr = get_current_Thread_in_C_C();
1910 Thr* hbthr = thr->hbthr;
sewardj23f12002009-07-24 08:45:08 +00001911 LIBHB_CWRITE_N(hbthr, a, size);
sewardjb4112022007-11-09 22:49:28 +00001912}
1913
sewardjb4112022007-11-09 22:49:28 +00001914
sewardj9f569b72008-11-13 13:33:09 +00001915/* ------------------------------------------------------- */
sewardjb4112022007-11-09 22:49:28 +00001916/* -------------- events to do with mutexes -------------- */
sewardj9f569b72008-11-13 13:33:09 +00001917/* ------------------------------------------------------- */
sewardjb4112022007-11-09 22:49:28 +00001918
1919/* EXPOSITION only: by intercepting lock init events we can show the
1920 user where the lock was initialised, rather than only being able to
1921 show where it was first locked. Intercepting lock initialisations
1922 is not necessary for the basic operation of the race checker. */
1923static
1924void evh__HG_PTHREAD_MUTEX_INIT_POST( ThreadId tid,
1925 void* mutex, Word mbRec )
1926{
1927 if (SHOW_EVENTS >= 1)
1928 VG_(printf)("evh__hg_PTHREAD_MUTEX_INIT_POST(ctid=%d, mbRec=%ld, %p)\n",
1929 (Int)tid, mbRec, (void*)mutex );
1930 tl_assert(mbRec == 0 || mbRec == 1);
1931 map_locks_lookup_or_create( mbRec ? LK_mbRec : LK_nonRec,
1932 (Addr)mutex, tid );
sewardjf98e1c02008-10-25 16:22:41 +00001933 if (HG_(clo_sanity_flags) & SCE_LOCKS)
sewardjb4112022007-11-09 22:49:28 +00001934 all__sanity_check("evh__hg_PTHREAD_MUTEX_INIT_POST");
1935}
1936
1937static
sewardjc02f6c42013-10-14 13:51:25 +00001938void evh__HG_PTHREAD_MUTEX_DESTROY_PRE( ThreadId tid, void* mutex,
1939 Bool mutex_is_init )
sewardjb4112022007-11-09 22:49:28 +00001940{
1941 Thread* thr;
1942 Lock* lk;
1943 if (SHOW_EVENTS >= 1)
sewardjc02f6c42013-10-14 13:51:25 +00001944 VG_(printf)("evh__hg_PTHREAD_MUTEX_DESTROY_PRE"
1945 "(ctid=%d, %p, isInit=%d)\n",
1946 (Int)tid, (void*)mutex, (Int)mutex_is_init );
sewardjb4112022007-11-09 22:49:28 +00001947
1948 thr = map_threads_maybe_lookup( tid );
1949 /* cannot fail - Thread* must already exist */
sewardjf98e1c02008-10-25 16:22:41 +00001950 tl_assert( HG_(is_sane_Thread)(thr) );
sewardjb4112022007-11-09 22:49:28 +00001951
1952 lk = map_locks_maybe_lookup( (Addr)mutex );
1953
sewardjc02f6c42013-10-14 13:51:25 +00001954 if (lk == NULL && mutex_is_init) {
1955 /* We're destroying a mutex which we don't have any record of,
1956 and which appears to have the value PTHREAD_MUTEX_INITIALIZER.
1957 Assume it never got used, and so we don't need to do anything
1958 more. */
1959 goto out;
1960 }
1961
sewardjb4112022007-11-09 22:49:28 +00001962 if (lk == NULL || (lk->kind != LK_nonRec && lk->kind != LK_mbRec)) {
sewardjf98e1c02008-10-25 16:22:41 +00001963 HG_(record_error_Misc)(
1964 thr, "pthread_mutex_destroy with invalid argument" );
sewardjb4112022007-11-09 22:49:28 +00001965 }
1966
1967 if (lk) {
sewardjf98e1c02008-10-25 16:22:41 +00001968 tl_assert( HG_(is_sane_LockN)(lk) );
sewardjb4112022007-11-09 22:49:28 +00001969 tl_assert( lk->guestaddr == (Addr)mutex );
1970 if (lk->heldBy) {
1971 /* Basically act like we unlocked the lock */
sewardjf98e1c02008-10-25 16:22:41 +00001972 HG_(record_error_Misc)(
1973 thr, "pthread_mutex_destroy of a locked mutex" );
sewardjb4112022007-11-09 22:49:28 +00001974 /* remove lock from locksets of all owning threads */
1975 remove_Lock_from_locksets_of_all_owning_Threads( lk );
sewardj896f6f92008-08-19 08:38:52 +00001976 VG_(deleteBag)( lk->heldBy );
sewardjb4112022007-11-09 22:49:28 +00001977 lk->heldBy = NULL;
1978 lk->heldW = False;
1979 lk->acquired_at = NULL;
1980 }
1981 tl_assert( !lk->heldBy );
sewardjf98e1c02008-10-25 16:22:41 +00001982 tl_assert( HG_(is_sane_LockN)(lk) );
sewardjc1fb9d22011-02-28 09:03:44 +00001983
1984 if (HG_(clo_track_lockorders))
1985 laog__handle_one_lock_deletion(lk);
sewardjf98e1c02008-10-25 16:22:41 +00001986 map_locks_delete( lk->guestaddr );
1987 del_LockN( lk );
sewardjb4112022007-11-09 22:49:28 +00001988 }
1989
sewardjc02f6c42013-10-14 13:51:25 +00001990 out:
sewardjf98e1c02008-10-25 16:22:41 +00001991 if (HG_(clo_sanity_flags) & SCE_LOCKS)
sewardjb4112022007-11-09 22:49:28 +00001992 all__sanity_check("evh__hg_PTHREAD_MUTEX_DESTROY_PRE");
1993}
1994
1995static void evh__HG_PTHREAD_MUTEX_LOCK_PRE ( ThreadId tid,
1996 void* mutex, Word isTryLock )
1997{
1998 /* Just check the mutex is sane; nothing else to do. */
1999 // 'mutex' may be invalid - not checked by wrapper
2000 Thread* thr;
2001 Lock* lk;
2002 if (SHOW_EVENTS >= 1)
2003 VG_(printf)("evh__hg_PTHREAD_MUTEX_LOCK_PRE(ctid=%d, mutex=%p)\n",
2004 (Int)tid, (void*)mutex );
2005
2006 tl_assert(isTryLock == 0 || isTryLock == 1);
2007 thr = map_threads_maybe_lookup( tid );
2008 tl_assert(thr); /* cannot fail - Thread* must already exist */
2009
2010 lk = map_locks_maybe_lookup( (Addr)mutex );
2011
2012 if (lk && (lk->kind == LK_rdwr)) {
sewardjf98e1c02008-10-25 16:22:41 +00002013 HG_(record_error_Misc)( thr, "pthread_mutex_lock with a "
2014 "pthread_rwlock_t* argument " );
sewardjb4112022007-11-09 22:49:28 +00002015 }
2016
2017 if ( lk
2018 && isTryLock == 0
2019 && (lk->kind == LK_nonRec || lk->kind == LK_rdwr)
2020 && lk->heldBy
2021 && lk->heldW
florian6bf37262012-10-21 03:23:36 +00002022 && VG_(elemBag)( lk->heldBy, (UWord)thr ) > 0 ) {
sewardjb4112022007-11-09 22:49:28 +00002023 /* uh, it's a non-recursive lock and we already w-hold it, and
2024 this is a real lock operation (not a speculative "tryLock"
2025 kind of thing). Duh. Deadlock coming up; but at least
2026 produce an error message. */
florian6bd9dc12012-11-23 16:17:43 +00002027 const HChar* errstr = "Attempt to re-lock a "
2028 "non-recursive lock I already hold";
2029 const HChar* auxstr = "Lock was previously acquired";
sewardj8fef6252010-07-29 05:28:02 +00002030 if (lk->acquired_at) {
2031 HG_(record_error_Misc_w_aux)( thr, errstr, auxstr, lk->acquired_at );
2032 } else {
2033 HG_(record_error_Misc)( thr, errstr );
2034 }
sewardjb4112022007-11-09 22:49:28 +00002035 }
2036}
2037
2038static void evh__HG_PTHREAD_MUTEX_LOCK_POST ( ThreadId tid, void* mutex )
2039{
2040 // only called if the real library call succeeded - so mutex is sane
2041 Thread* thr;
2042 if (SHOW_EVENTS >= 1)
2043 VG_(printf)("evh__HG_PTHREAD_MUTEX_LOCK_POST(ctid=%d, mutex=%p)\n",
2044 (Int)tid, (void*)mutex );
2045
2046 thr = map_threads_maybe_lookup( tid );
2047 tl_assert(thr); /* cannot fail - Thread* must already exist */
2048
2049 evhH__post_thread_w_acquires_lock(
2050 thr,
2051 LK_mbRec, /* if not known, create new lock with this LockKind */
2052 (Addr)mutex
2053 );
2054}
2055
2056static void evh__HG_PTHREAD_MUTEX_UNLOCK_PRE ( ThreadId tid, void* mutex )
2057{
2058 // 'mutex' may be invalid - not checked by wrapper
2059 Thread* thr;
2060 if (SHOW_EVENTS >= 1)
2061 VG_(printf)("evh__HG_PTHREAD_MUTEX_UNLOCK_PRE(ctid=%d, mutex=%p)\n",
2062 (Int)tid, (void*)mutex );
2063
2064 thr = map_threads_maybe_lookup( tid );
2065 tl_assert(thr); /* cannot fail - Thread* must already exist */
2066
2067 evhH__pre_thread_releases_lock( thr, (Addr)mutex, False/*!isRDWR*/ );
2068}
2069
2070static void evh__HG_PTHREAD_MUTEX_UNLOCK_POST ( ThreadId tid, void* mutex )
2071{
2072 // only called if the real library call succeeded - so mutex is sane
2073 Thread* thr;
2074 if (SHOW_EVENTS >= 1)
2075 VG_(printf)("evh__hg_PTHREAD_MUTEX_UNLOCK_POST(ctid=%d, mutex=%p)\n",
2076 (Int)tid, (void*)mutex );
2077 thr = map_threads_maybe_lookup( tid );
2078 tl_assert(thr); /* cannot fail - Thread* must already exist */
2079
2080 // anything we should do here?
2081}
2082
2083
sewardj5a644da2009-08-11 10:35:58 +00002084/* ------------------------------------------------------- */
sewardj1f77fec2010-04-12 19:51:04 +00002085/* -------------- events to do with spinlocks ------------ */
sewardj5a644da2009-08-11 10:35:58 +00002086/* ------------------------------------------------------- */
2087
2088/* All a bit of a kludge. Pretend we're really dealing with ordinary
2089 pthread_mutex_t's instead, for the most part. */
2090
2091static void evh__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE( ThreadId tid,
2092 void* slock )
2093{
2094 Thread* thr;
2095 Lock* lk;
2096 /* In glibc's kludgey world, we're either initialising or unlocking
2097 it. Since this is the pre-routine, if it is locked, unlock it
2098 and take a dependence edge. Otherwise, do nothing. */
2099
2100 if (SHOW_EVENTS >= 1)
2101 VG_(printf)("evh__hg_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE"
2102 "(ctid=%d, slock=%p)\n",
2103 (Int)tid, (void*)slock );
2104
2105 thr = map_threads_maybe_lookup( tid );
2106 /* cannot fail - Thread* must already exist */;
2107 tl_assert( HG_(is_sane_Thread)(thr) );
2108
2109 lk = map_locks_maybe_lookup( (Addr)slock );
2110 if (lk && lk->heldBy) {
2111 /* it's held. So do the normal pre-unlock actions, as copied
2112 from evh__HG_PTHREAD_MUTEX_UNLOCK_PRE. This stupidly
2113 duplicates the map_locks_maybe_lookup. */
2114 evhH__pre_thread_releases_lock( thr, (Addr)slock,
2115 False/*!isRDWR*/ );
2116 }
2117}
2118
2119static void evh__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST( ThreadId tid,
2120 void* slock )
2121{
2122 Lock* lk;
2123 /* More kludgery. If the lock has never been seen before, do
2124 actions as per evh__HG_PTHREAD_MUTEX_INIT_POST. Else do
2125 nothing. */
2126
2127 if (SHOW_EVENTS >= 1)
2128 VG_(printf)("evh__hg_PTHREAD_SPIN_INIT_OR_UNLOCK_POST"
2129 "(ctid=%d, slock=%p)\n",
2130 (Int)tid, (void*)slock );
2131
2132 lk = map_locks_maybe_lookup( (Addr)slock );
2133 if (!lk) {
2134 map_locks_lookup_or_create( LK_nonRec, (Addr)slock, tid );
2135 }
2136}
2137
2138static void evh__HG_PTHREAD_SPIN_LOCK_PRE( ThreadId tid,
2139 void* slock, Word isTryLock )
2140{
2141 evh__HG_PTHREAD_MUTEX_LOCK_PRE( tid, slock, isTryLock );
2142}
2143
2144static void evh__HG_PTHREAD_SPIN_LOCK_POST( ThreadId tid,
2145 void* slock )
2146{
2147 evh__HG_PTHREAD_MUTEX_LOCK_POST( tid, slock );
2148}
2149
2150static void evh__HG_PTHREAD_SPIN_DESTROY_PRE( ThreadId tid,
2151 void* slock )
2152{
sewardjc02f6c42013-10-14 13:51:25 +00002153 evh__HG_PTHREAD_MUTEX_DESTROY_PRE( tid, slock, 0/*!isInit*/ );
sewardj5a644da2009-08-11 10:35:58 +00002154}
2155
2156
sewardj9f569b72008-11-13 13:33:09 +00002157/* ----------------------------------------------------- */
sewardjb4112022007-11-09 22:49:28 +00002158/* --------------- events to do with CVs --------------- */
sewardj9f569b72008-11-13 13:33:09 +00002159/* ----------------------------------------------------- */
sewardjb4112022007-11-09 22:49:28 +00002160
sewardj02114542009-07-28 20:52:36 +00002161/* A mapping from CV to (the SO associated with it, plus some
2162 auxiliary data for error checking). When the CV is
sewardjf98e1c02008-10-25 16:22:41 +00002163 signalled/broadcasted upon, we do a 'send' into the SO, and when a
2164 wait on it completes, we do a 'recv' from the SO. This is believed
2165 to give the correct happens-before events arising from CV
sewardjb4112022007-11-09 22:49:28 +00002166 signallings/broadcasts.
2167*/
2168
sewardj02114542009-07-28 20:52:36 +00002169/* .so is the SO for this CV.
2170 .mx_ga is the associated mutex, when .nWaiters > 0
sewardjb4112022007-11-09 22:49:28 +00002171
sewardj02114542009-07-28 20:52:36 +00002172 POSIX says effectively that the first pthread_cond_{timed}wait call
2173 causes a dynamic binding between the CV and the mutex, and that
2174 lasts until such time as the waiter count falls to zero. Hence
2175 need to keep track of the number of waiters in order to do
2176 consistency tracking. */
2177typedef
2178 struct {
2179 SO* so; /* libhb-allocated SO */
2180 void* mx_ga; /* addr of associated mutex, if any */
2181 UWord nWaiters; /* # threads waiting on the CV */
2182 }
2183 CVInfo;
2184
2185
2186/* pthread_cond_t* -> CVInfo* */
2187static WordFM* map_cond_to_CVInfo = NULL;
2188
2189static void map_cond_to_CVInfo_INIT ( void ) {
2190 if (UNLIKELY(map_cond_to_CVInfo == NULL)) {
2191 map_cond_to_CVInfo = VG_(newFM)( HG_(zalloc),
2192 "hg.mctCI.1", HG_(free), NULL );
sewardjf98e1c02008-10-25 16:22:41 +00002193 }
2194}
2195
sewardj02114542009-07-28 20:52:36 +00002196static CVInfo* map_cond_to_CVInfo_lookup_or_alloc ( void* cond ) {
sewardjf98e1c02008-10-25 16:22:41 +00002197 UWord key, val;
sewardj02114542009-07-28 20:52:36 +00002198 map_cond_to_CVInfo_INIT();
2199 if (VG_(lookupFM)( map_cond_to_CVInfo, &key, &val, (UWord)cond )) {
sewardjf98e1c02008-10-25 16:22:41 +00002200 tl_assert(key == (UWord)cond);
sewardj02114542009-07-28 20:52:36 +00002201 return (CVInfo*)val;
sewardjf98e1c02008-10-25 16:22:41 +00002202 } else {
sewardj02114542009-07-28 20:52:36 +00002203 SO* so = libhb_so_alloc();
2204 CVInfo* cvi = HG_(zalloc)("hg.mctCloa.1", sizeof(CVInfo));
2205 cvi->so = so;
2206 cvi->mx_ga = 0;
2207 VG_(addToFM)( map_cond_to_CVInfo, (UWord)cond, (UWord)cvi );
2208 return cvi;
sewardjf98e1c02008-10-25 16:22:41 +00002209 }
2210}
2211
philippe8bfc2152012-07-06 23:38:24 +00002212static CVInfo* map_cond_to_CVInfo_lookup_NO_alloc ( void* cond ) {
2213 UWord key, val;
2214 map_cond_to_CVInfo_INIT();
2215 if (VG_(lookupFM)( map_cond_to_CVInfo, &key, &val, (UWord)cond )) {
2216 tl_assert(key == (UWord)cond);
2217 return (CVInfo*)val;
2218 } else {
2219 return NULL;
2220 }
2221}
2222
sewardjc02f6c42013-10-14 13:51:25 +00002223static void map_cond_to_CVInfo_delete ( ThreadId tid,
2224 void* cond, Bool cond_is_init ) {
philippe8bfc2152012-07-06 23:38:24 +00002225 Thread* thr;
sewardjf98e1c02008-10-25 16:22:41 +00002226 UWord keyW, valW;
philippe8bfc2152012-07-06 23:38:24 +00002227
2228 thr = map_threads_maybe_lookup( tid );
2229 tl_assert(thr); /* cannot fail - Thread* must already exist */
2230
sewardj02114542009-07-28 20:52:36 +00002231 map_cond_to_CVInfo_INIT();
philippe24111972013-03-18 22:48:22 +00002232 if (VG_(lookupFM)( map_cond_to_CVInfo, &keyW, &valW, (UWord)cond )) {
sewardj02114542009-07-28 20:52:36 +00002233 CVInfo* cvi = (CVInfo*)valW;
sewardjf98e1c02008-10-25 16:22:41 +00002234 tl_assert(keyW == (UWord)cond);
sewardj02114542009-07-28 20:52:36 +00002235 tl_assert(cvi);
2236 tl_assert(cvi->so);
philippe8bfc2152012-07-06 23:38:24 +00002237 if (cvi->nWaiters > 0) {
sewardjc02f6c42013-10-14 13:51:25 +00002238 HG_(record_error_Misc)(
2239 thr, "pthread_cond_destroy:"
2240 " destruction of condition variable being waited upon");
philippe24111972013-03-18 22:48:22 +00002241 /* Destroying a cond var being waited upon outcome is EBUSY and
2242 variable is not destroyed. */
2243 return;
philippe8bfc2152012-07-06 23:38:24 +00002244 }
philippe24111972013-03-18 22:48:22 +00002245 if (!VG_(delFromFM)( map_cond_to_CVInfo, &keyW, &valW, (UWord)cond ))
2246 tl_assert(0); // cond var found above, and not here ???
sewardj02114542009-07-28 20:52:36 +00002247 libhb_so_dealloc(cvi->so);
2248 cvi->mx_ga = 0;
2249 HG_(free)(cvi);
philippe8bfc2152012-07-06 23:38:24 +00002250 } else {
sewardjc02f6c42013-10-14 13:51:25 +00002251 /* We have no record of this CV. So complain about it
2252 .. except, don't bother to complain if it has exactly the
2253 value PTHREAD_COND_INITIALIZER, since it might be that the CV
2254 was initialised like that but never used. */
2255 if (!cond_is_init) {
2256 HG_(record_error_Misc)(
2257 thr, "pthread_cond_destroy: destruction of unknown cond var");
2258 }
sewardjb4112022007-11-09 22:49:28 +00002259 }
2260}
2261
2262static void evh__HG_PTHREAD_COND_SIGNAL_PRE ( ThreadId tid, void* cond )
2263{
sewardjf98e1c02008-10-25 16:22:41 +00002264 /* 'tid' has signalled on 'cond'. As per the comment above, bind
2265 cond to a SO if it is not already so bound, and 'send' on the
2266 SO. This is later used by other thread(s) which successfully
2267 exit from a pthread_cond_wait on the same cv; then they 'recv'
2268 from the SO, thereby acquiring a dependency on this signalling
2269 event. */
sewardjb4112022007-11-09 22:49:28 +00002270 Thread* thr;
sewardj02114542009-07-28 20:52:36 +00002271 CVInfo* cvi;
2272 //Lock* lk;
sewardjb4112022007-11-09 22:49:28 +00002273
2274 if (SHOW_EVENTS >= 1)
2275 VG_(printf)("evh__HG_PTHREAD_COND_SIGNAL_PRE(ctid=%d, cond=%p)\n",
2276 (Int)tid, (void*)cond );
2277
sewardjb4112022007-11-09 22:49:28 +00002278 thr = map_threads_maybe_lookup( tid );
2279 tl_assert(thr); /* cannot fail - Thread* must already exist */
2280
sewardj02114542009-07-28 20:52:36 +00002281 cvi = map_cond_to_CVInfo_lookup_or_alloc( cond );
2282 tl_assert(cvi);
2283 tl_assert(cvi->so);
2284
sewardjb4112022007-11-09 22:49:28 +00002285 // error-if: mutex is bogus
2286 // error-if: mutex is not locked
sewardj02114542009-07-28 20:52:36 +00002287 // Hmm. POSIX doesn't actually say that it's an error to call
2288 // pthread_cond_signal with the associated mutex being unlocked.
2289 // Although it does say that it should be "if consistent scheduling
sewardjffce8152011-06-24 10:09:41 +00002290 // is desired." For that reason, print "dubious" if the lock isn't
2291 // held by any thread. Skip the "dubious" if it is held by some
2292 // other thread; that sounds straight-out wrong.
sewardj02114542009-07-28 20:52:36 +00002293 //
sewardjffce8152011-06-24 10:09:41 +00002294 // Anybody who writes code that signals on a CV without holding
2295 // the associated MX needs to be shipped off to a lunatic asylum
2296 // ASAP, even though POSIX doesn't actually declare such behaviour
2297 // illegal -- it makes code extremely difficult to understand/
2298 // reason about. In particular it puts the signalling thread in
2299 // a situation where it is racing against the released waiter
2300 // as soon as the signalling is done, and so there needs to be
2301 // some auxiliary synchronisation mechanism in the program that
2302 // makes this safe -- or the race(s) need to be harmless, or
2303 // probably nonexistent.
2304 //
2305 if (1) {
2306 Lock* lk = NULL;
2307 if (cvi->mx_ga != 0) {
2308 lk = map_locks_maybe_lookup( (Addr)cvi->mx_ga );
2309 }
2310 /* note: lk could be NULL. Be careful. */
2311 if (lk) {
2312 if (lk->kind == LK_rdwr) {
2313 HG_(record_error_Misc)(thr,
2314 "pthread_cond_{signal,broadcast}: associated lock is a rwlock");
2315 }
2316 if (lk->heldBy == NULL) {
2317 HG_(record_error_Misc)(thr,
2318 "pthread_cond_{signal,broadcast}: dubious: "
2319 "associated lock is not held by any thread");
2320 }
florian6bf37262012-10-21 03:23:36 +00002321 if (lk->heldBy != NULL && 0 == VG_(elemBag)(lk->heldBy, (UWord)thr)) {
sewardjffce8152011-06-24 10:09:41 +00002322 HG_(record_error_Misc)(thr,
2323 "pthread_cond_{signal,broadcast}: "
2324 "associated lock is not held by calling thread");
2325 }
2326 } else {
2327 /* Couldn't even find the damn thing. */
2328 // But actually .. that's not necessarily an error. We don't
2329 // know the (CV,MX) binding until a pthread_cond_wait or bcast
2330 // shows us what it is, and if that may not have happened yet.
2331 // So just keep quiet in this circumstance.
2332 //HG_(record_error_Misc)( thr,
2333 // "pthread_cond_{signal,broadcast}: "
2334 // "no or invalid mutex associated with cond");
2335 }
2336 }
sewardjb4112022007-11-09 22:49:28 +00002337
sewardj02114542009-07-28 20:52:36 +00002338 libhb_so_send( thr->hbthr, cvi->so, True/*strong_send*/ );
sewardjb4112022007-11-09 22:49:28 +00002339}
2340
2341/* returns True if it reckons 'mutex' is valid and held by this
2342 thread, else False */
2343static Bool evh__HG_PTHREAD_COND_WAIT_PRE ( ThreadId tid,
2344 void* cond, void* mutex )
2345{
2346 Thread* thr;
2347 Lock* lk;
2348 Bool lk_valid = True;
sewardj02114542009-07-28 20:52:36 +00002349 CVInfo* cvi;
sewardjb4112022007-11-09 22:49:28 +00002350
2351 if (SHOW_EVENTS >= 1)
2352 VG_(printf)("evh__hg_PTHREAD_COND_WAIT_PRE"
2353 "(ctid=%d, cond=%p, mutex=%p)\n",
2354 (Int)tid, (void*)cond, (void*)mutex );
2355
sewardjb4112022007-11-09 22:49:28 +00002356 thr = map_threads_maybe_lookup( tid );
2357 tl_assert(thr); /* cannot fail - Thread* must already exist */
2358
2359 lk = map_locks_maybe_lookup( (Addr)mutex );
2360
2361 /* Check for stupid mutex arguments. There are various ways to be
2362 a bozo. Only complain once, though, even if more than one thing
2363 is wrong. */
2364 if (lk == NULL) {
2365 lk_valid = False;
sewardjf98e1c02008-10-25 16:22:41 +00002366 HG_(record_error_Misc)(
sewardjb4112022007-11-09 22:49:28 +00002367 thr,
2368 "pthread_cond_{timed}wait called with invalid mutex" );
2369 } else {
sewardjf98e1c02008-10-25 16:22:41 +00002370 tl_assert( HG_(is_sane_LockN)(lk) );
sewardjb4112022007-11-09 22:49:28 +00002371 if (lk->kind == LK_rdwr) {
2372 lk_valid = False;
sewardjf98e1c02008-10-25 16:22:41 +00002373 HG_(record_error_Misc)(
sewardjb4112022007-11-09 22:49:28 +00002374 thr, "pthread_cond_{timed}wait called with mutex "
2375 "of type pthread_rwlock_t*" );
2376 } else
2377 if (lk->heldBy == NULL) {
2378 lk_valid = False;
sewardjf98e1c02008-10-25 16:22:41 +00002379 HG_(record_error_Misc)(
sewardjb4112022007-11-09 22:49:28 +00002380 thr, "pthread_cond_{timed}wait called with un-held mutex");
2381 } else
2382 if (lk->heldBy != NULL
florian6bf37262012-10-21 03:23:36 +00002383 && VG_(elemBag)( lk->heldBy, (UWord)thr ) == 0) {
sewardjb4112022007-11-09 22:49:28 +00002384 lk_valid = False;
sewardjf98e1c02008-10-25 16:22:41 +00002385 HG_(record_error_Misc)(
sewardjb4112022007-11-09 22:49:28 +00002386 thr, "pthread_cond_{timed}wait called with mutex "
2387 "held by a different thread" );
2388 }
2389 }
2390
2391 // error-if: cond is also associated with a different mutex
sewardj02114542009-07-28 20:52:36 +00002392 cvi = map_cond_to_CVInfo_lookup_or_alloc(cond);
2393 tl_assert(cvi);
2394 tl_assert(cvi->so);
2395 if (cvi->nWaiters == 0) {
2396 /* form initial (CV,MX) binding */
2397 cvi->mx_ga = mutex;
2398 }
2399 else /* check existing (CV,MX) binding */
2400 if (cvi->mx_ga != mutex) {
2401 HG_(record_error_Misc)(
2402 thr, "pthread_cond_{timed}wait: cond is associated "
2403 "with a different mutex");
2404 }
2405 cvi->nWaiters++;
sewardjb4112022007-11-09 22:49:28 +00002406
2407 return lk_valid;
2408}
2409
2410static void evh__HG_PTHREAD_COND_WAIT_POST ( ThreadId tid,
sewardjff427c92013-10-14 12:13:52 +00002411 void* cond, void* mutex,
2412 Bool timeout)
sewardjb4112022007-11-09 22:49:28 +00002413{
sewardjf98e1c02008-10-25 16:22:41 +00002414 /* A pthread_cond_wait(cond, mutex) completed successfully. Find
2415 the SO for this cond, and 'recv' from it so as to acquire a
2416 dependency edge back to the signaller/broadcaster. */
2417 Thread* thr;
sewardj02114542009-07-28 20:52:36 +00002418 CVInfo* cvi;
sewardjb4112022007-11-09 22:49:28 +00002419
2420 if (SHOW_EVENTS >= 1)
2421 VG_(printf)("evh__HG_PTHREAD_COND_WAIT_POST"
sewardjff427c92013-10-14 12:13:52 +00002422 "(ctid=%d, cond=%p, mutex=%p)\n, timeout=%d",
2423 (Int)tid, (void*)cond, (void*)mutex, (Int)timeout );
sewardjb4112022007-11-09 22:49:28 +00002424
sewardjb4112022007-11-09 22:49:28 +00002425 thr = map_threads_maybe_lookup( tid );
2426 tl_assert(thr); /* cannot fail - Thread* must already exist */
2427
2428 // error-if: cond is also associated with a different mutex
2429
philippe8bfc2152012-07-06 23:38:24 +00002430 cvi = map_cond_to_CVInfo_lookup_NO_alloc( cond );
2431 if (!cvi) {
2432 /* This could be either a bug in helgrind or the guest application
2433 that did an error (e.g. cond var was destroyed by another thread.
2434 Let's assume helgrind is perfect ...
2435 Note that this is similar to drd behaviour. */
2436 HG_(record_error_Misc)(thr, "condition variable has been destroyed while"
2437 " being waited upon");
2438 return;
2439 }
2440
sewardj02114542009-07-28 20:52:36 +00002441 tl_assert(cvi);
2442 tl_assert(cvi->so);
2443 tl_assert(cvi->nWaiters > 0);
sewardjb4112022007-11-09 22:49:28 +00002444
sewardjff427c92013-10-14 12:13:52 +00002445 if (!timeout && !libhb_so_everSent(cvi->so)) {
sewardjf98e1c02008-10-25 16:22:41 +00002446 /* Hmm. How can a wait on 'cond' succeed if nobody signalled
2447 it? If this happened it would surely be a bug in the threads
2448 library. Or one of those fabled "spurious wakeups". */
2449 HG_(record_error_Misc)( thr, "Bug in libpthread: pthread_cond_wait "
sewardjffce8152011-06-24 10:09:41 +00002450 "succeeded"
sewardjf98e1c02008-10-25 16:22:41 +00002451 " without prior pthread_cond_post");
sewardjb4112022007-11-09 22:49:28 +00002452 }
sewardjf98e1c02008-10-25 16:22:41 +00002453
2454 /* anyway, acquire a dependency on it. */
sewardj02114542009-07-28 20:52:36 +00002455 libhb_so_recv( thr->hbthr, cvi->so, True/*strong_recv*/ );
2456
2457 cvi->nWaiters--;
sewardjf98e1c02008-10-25 16:22:41 +00002458}
2459
philippe19dfe032013-03-24 20:10:23 +00002460static void evh__HG_PTHREAD_COND_INIT_POST ( ThreadId tid,
2461 void* cond, void* cond_attr )
2462{
2463 CVInfo* cvi;
2464
2465 if (SHOW_EVENTS >= 1)
2466 VG_(printf)("evh__HG_PTHREAD_COND_INIT_POST"
2467 "(ctid=%d, cond=%p, cond_attr=%p)\n",
2468 (Int)tid, (void*)cond, (void*) cond_attr );
2469
2470 cvi = map_cond_to_CVInfo_lookup_or_alloc( cond );
2471 tl_assert (cvi);
2472 tl_assert (cvi->so);
2473}
2474
2475
sewardjf98e1c02008-10-25 16:22:41 +00002476static void evh__HG_PTHREAD_COND_DESTROY_PRE ( ThreadId tid,
sewardjc02f6c42013-10-14 13:51:25 +00002477 void* cond, Bool cond_is_init )
sewardjf98e1c02008-10-25 16:22:41 +00002478{
2479 /* Deal with destroy events. The only purpose is to free storage
2480 associated with the CV, so as to avoid any possible resource
2481 leaks. */
2482 if (SHOW_EVENTS >= 1)
2483 VG_(printf)("evh__HG_PTHREAD_COND_DESTROY_PRE"
sewardjc02f6c42013-10-14 13:51:25 +00002484 "(ctid=%d, cond=%p, cond_is_init=%d)\n",
2485 (Int)tid, (void*)cond, (Int)cond_is_init );
sewardjf98e1c02008-10-25 16:22:41 +00002486
sewardjc02f6c42013-10-14 13:51:25 +00002487 map_cond_to_CVInfo_delete( tid, cond, cond_is_init );
sewardjb4112022007-11-09 22:49:28 +00002488}
2489
2490
sewardj9f569b72008-11-13 13:33:09 +00002491/* ------------------------------------------------------- */
sewardjb4112022007-11-09 22:49:28 +00002492/* -------------- events to do with rwlocks -------------- */
sewardj9f569b72008-11-13 13:33:09 +00002493/* ------------------------------------------------------- */
sewardjb4112022007-11-09 22:49:28 +00002494
2495/* EXPOSITION only */
2496static
2497void evh__HG_PTHREAD_RWLOCK_INIT_POST( ThreadId tid, void* rwl )
2498{
2499 if (SHOW_EVENTS >= 1)
2500 VG_(printf)("evh__hg_PTHREAD_RWLOCK_INIT_POST(ctid=%d, %p)\n",
2501 (Int)tid, (void*)rwl );
2502 map_locks_lookup_or_create( LK_rdwr, (Addr)rwl, tid );
sewardjf98e1c02008-10-25 16:22:41 +00002503 if (HG_(clo_sanity_flags) & SCE_LOCKS)
sewardjb4112022007-11-09 22:49:28 +00002504 all__sanity_check("evh__hg_PTHREAD_RWLOCK_INIT_POST");
2505}
2506
2507static
2508void evh__HG_PTHREAD_RWLOCK_DESTROY_PRE( ThreadId tid, void* rwl )
2509{
2510 Thread* thr;
2511 Lock* lk;
2512 if (SHOW_EVENTS >= 1)
2513 VG_(printf)("evh__hg_PTHREAD_RWLOCK_DESTROY_PRE(ctid=%d, %p)\n",
2514 (Int)tid, (void*)rwl );
2515
2516 thr = map_threads_maybe_lookup( tid );
2517 /* cannot fail - Thread* must already exist */
sewardjf98e1c02008-10-25 16:22:41 +00002518 tl_assert( HG_(is_sane_Thread)(thr) );
sewardjb4112022007-11-09 22:49:28 +00002519
2520 lk = map_locks_maybe_lookup( (Addr)rwl );
2521
2522 if (lk == NULL || lk->kind != LK_rdwr) {
sewardjf98e1c02008-10-25 16:22:41 +00002523 HG_(record_error_Misc)(
2524 thr, "pthread_rwlock_destroy with invalid argument" );
sewardjb4112022007-11-09 22:49:28 +00002525 }
2526
2527 if (lk) {
sewardjf98e1c02008-10-25 16:22:41 +00002528 tl_assert( HG_(is_sane_LockN)(lk) );
sewardjb4112022007-11-09 22:49:28 +00002529 tl_assert( lk->guestaddr == (Addr)rwl );
2530 if (lk->heldBy) {
2531 /* Basically act like we unlocked the lock */
sewardjf98e1c02008-10-25 16:22:41 +00002532 HG_(record_error_Misc)(
2533 thr, "pthread_rwlock_destroy of a locked mutex" );
sewardjb4112022007-11-09 22:49:28 +00002534 /* remove lock from locksets of all owning threads */
2535 remove_Lock_from_locksets_of_all_owning_Threads( lk );
sewardj896f6f92008-08-19 08:38:52 +00002536 VG_(deleteBag)( lk->heldBy );
sewardjb4112022007-11-09 22:49:28 +00002537 lk->heldBy = NULL;
2538 lk->heldW = False;
sewardj1c7e8332007-11-29 13:04:03 +00002539 lk->acquired_at = NULL;
sewardjb4112022007-11-09 22:49:28 +00002540 }
2541 tl_assert( !lk->heldBy );
sewardjf98e1c02008-10-25 16:22:41 +00002542 tl_assert( HG_(is_sane_LockN)(lk) );
sewardjc1fb9d22011-02-28 09:03:44 +00002543
2544 if (HG_(clo_track_lockorders))
2545 laog__handle_one_lock_deletion(lk);
sewardjf98e1c02008-10-25 16:22:41 +00002546 map_locks_delete( lk->guestaddr );
2547 del_LockN( lk );
sewardjb4112022007-11-09 22:49:28 +00002548 }
2549
sewardjf98e1c02008-10-25 16:22:41 +00002550 if (HG_(clo_sanity_flags) & SCE_LOCKS)
sewardjb4112022007-11-09 22:49:28 +00002551 all__sanity_check("evh__hg_PTHREAD_RWLOCK_DESTROY_PRE");
2552}
2553
2554static
sewardj789c3c52008-02-25 12:10:07 +00002555void evh__HG_PTHREAD_RWLOCK_LOCK_PRE ( ThreadId tid,
2556 void* rwl,
2557 Word isW, Word isTryLock )
sewardjb4112022007-11-09 22:49:28 +00002558{
2559 /* Just check the rwl is sane; nothing else to do. */
2560 // 'rwl' may be invalid - not checked by wrapper
2561 Thread* thr;
2562 Lock* lk;
2563 if (SHOW_EVENTS >= 1)
2564 VG_(printf)("evh__hg_PTHREAD_RWLOCK_LOCK_PRE(ctid=%d, isW=%d, %p)\n",
2565 (Int)tid, (Int)isW, (void*)rwl );
2566
2567 tl_assert(isW == 0 || isW == 1); /* assured us by wrapper */
sewardj789c3c52008-02-25 12:10:07 +00002568 tl_assert(isTryLock == 0 || isTryLock == 1); /* assured us by wrapper */
sewardjb4112022007-11-09 22:49:28 +00002569 thr = map_threads_maybe_lookup( tid );
2570 tl_assert(thr); /* cannot fail - Thread* must already exist */
2571
2572 lk = map_locks_maybe_lookup( (Addr)rwl );
2573 if ( lk
2574 && (lk->kind == LK_nonRec || lk->kind == LK_mbRec) ) {
2575 /* Wrong kind of lock. Duh. */
sewardjf98e1c02008-10-25 16:22:41 +00002576 HG_(record_error_Misc)(
2577 thr, "pthread_rwlock_{rd,rw}lock with a "
2578 "pthread_mutex_t* argument " );
sewardjb4112022007-11-09 22:49:28 +00002579 }
2580}
2581
2582static
2583void evh__HG_PTHREAD_RWLOCK_LOCK_POST ( ThreadId tid, void* rwl, Word isW )
2584{
2585 // only called if the real library call succeeded - so mutex is sane
2586 Thread* thr;
2587 if (SHOW_EVENTS >= 1)
2588 VG_(printf)("evh__hg_PTHREAD_RWLOCK_LOCK_POST(ctid=%d, isW=%d, %p)\n",
2589 (Int)tid, (Int)isW, (void*)rwl );
2590
2591 tl_assert(isW == 0 || isW == 1); /* assured us by wrapper */
2592 thr = map_threads_maybe_lookup( tid );
2593 tl_assert(thr); /* cannot fail - Thread* must already exist */
2594
2595 (isW ? evhH__post_thread_w_acquires_lock
2596 : evhH__post_thread_r_acquires_lock)(
2597 thr,
2598 LK_rdwr, /* if not known, create new lock with this LockKind */
2599 (Addr)rwl
2600 );
2601}
2602
2603static void evh__HG_PTHREAD_RWLOCK_UNLOCK_PRE ( ThreadId tid, void* rwl )
2604{
2605 // 'rwl' may be invalid - not checked by wrapper
2606 Thread* thr;
2607 if (SHOW_EVENTS >= 1)
2608 VG_(printf)("evh__HG_PTHREAD_RWLOCK_UNLOCK_PRE(ctid=%d, rwl=%p)\n",
2609 (Int)tid, (void*)rwl );
2610
2611 thr = map_threads_maybe_lookup( tid );
2612 tl_assert(thr); /* cannot fail - Thread* must already exist */
2613
2614 evhH__pre_thread_releases_lock( thr, (Addr)rwl, True/*isRDWR*/ );
2615}
2616
2617static void evh__HG_PTHREAD_RWLOCK_UNLOCK_POST ( ThreadId tid, void* rwl )
2618{
2619 // only called if the real library call succeeded - so mutex is sane
2620 Thread* thr;
2621 if (SHOW_EVENTS >= 1)
2622 VG_(printf)("evh__hg_PTHREAD_RWLOCK_UNLOCK_POST(ctid=%d, rwl=%p)\n",
2623 (Int)tid, (void*)rwl );
2624 thr = map_threads_maybe_lookup( tid );
2625 tl_assert(thr); /* cannot fail - Thread* must already exist */
2626
2627 // anything we should do here?
2628}
2629
2630
sewardj9f569b72008-11-13 13:33:09 +00002631/* ---------------------------------------------------------- */
2632/* -------------- events to do with semaphores -------------- */
2633/* ---------------------------------------------------------- */
sewardjb4112022007-11-09 22:49:28 +00002634
sewardj11e352f2007-11-30 11:11:02 +00002635/* This is similar to but not identical to the handling for condition
sewardjb4112022007-11-09 22:49:28 +00002636 variables. */
2637
sewardjf98e1c02008-10-25 16:22:41 +00002638/* For each semaphore, we maintain a stack of SOs. When a 'post'
2639 operation is done on a semaphore (unlocking, essentially), a new SO
2640 is created for the posting thread, the posting thread does a strong
2641 send to it (which merely installs the posting thread's VC in the
2642 SO), and the SO is pushed on the semaphore's stack.
sewardjb4112022007-11-09 22:49:28 +00002643
2644 Later, when a (probably different) thread completes 'wait' on the
sewardjf98e1c02008-10-25 16:22:41 +00002645 semaphore, we pop a SO off the semaphore's stack (which should be
2646 nonempty), and do a strong recv from it. This mechanism creates
sewardjb4112022007-11-09 22:49:28 +00002647 dependencies between posters and waiters of the semaphore.
2648
sewardjf98e1c02008-10-25 16:22:41 +00002649 It may not be necessary to use a stack - perhaps a bag of SOs would
2650 do. But we do need to keep track of how many unused-up posts have
2651 happened for the semaphore.
sewardjb4112022007-11-09 22:49:28 +00002652
sewardjf98e1c02008-10-25 16:22:41 +00002653 Imagine T1 and T2 both post once on a semaphore S, and T3 waits
sewardjb4112022007-11-09 22:49:28 +00002654 twice on S. T3 cannot complete its waits without both T1 and T2
2655 posting. The above mechanism will ensure that T3 acquires
2656 dependencies on both T1 and T2.
sewardj11e352f2007-11-30 11:11:02 +00002657
sewardjf98e1c02008-10-25 16:22:41 +00002658 When a semaphore is initialised with value N, we do as if we'd
2659 posted N times on the semaphore: basically create N SOs and do a
2660 strong send to all of then. This allows up to N waits on the
2661 semaphore to acquire a dependency on the initialisation point,
2662 which AFAICS is the correct behaviour.
sewardj11e352f2007-11-30 11:11:02 +00002663
2664 We don't emit an error for DESTROY_PRE on a semaphore we don't know
2665 about. We should.
sewardjb4112022007-11-09 22:49:28 +00002666*/
2667
sewardjf98e1c02008-10-25 16:22:41 +00002668/* sem_t* -> XArray* SO* */
2669static WordFM* map_sem_to_SO_stack = NULL;
sewardjb4112022007-11-09 22:49:28 +00002670
sewardjf98e1c02008-10-25 16:22:41 +00002671static void map_sem_to_SO_stack_INIT ( void ) {
2672 if (map_sem_to_SO_stack == NULL) {
2673 map_sem_to_SO_stack = VG_(newFM)( HG_(zalloc), "hg.mstSs.1",
2674 HG_(free), NULL );
sewardjb4112022007-11-09 22:49:28 +00002675 }
2676}
2677
sewardjf98e1c02008-10-25 16:22:41 +00002678static void push_SO_for_sem ( void* sem, SO* so ) {
2679 UWord keyW;
sewardjb4112022007-11-09 22:49:28 +00002680 XArray* xa;
sewardjf98e1c02008-10-25 16:22:41 +00002681 tl_assert(so);
2682 map_sem_to_SO_stack_INIT();
2683 if (VG_(lookupFM)( map_sem_to_SO_stack,
2684 &keyW, (UWord*)&xa, (UWord)sem )) {
2685 tl_assert(keyW == (UWord)sem);
sewardjb4112022007-11-09 22:49:28 +00002686 tl_assert(xa);
sewardjf98e1c02008-10-25 16:22:41 +00002687 VG_(addToXA)( xa, &so );
sewardjb4112022007-11-09 22:49:28 +00002688 } else {
sewardjf98e1c02008-10-25 16:22:41 +00002689 xa = VG_(newXA)( HG_(zalloc), "hg.pSfs.1", HG_(free), sizeof(SO*) );
2690 VG_(addToXA)( xa, &so );
florian6bf37262012-10-21 03:23:36 +00002691 VG_(addToFM)( map_sem_to_SO_stack, (UWord)sem, (UWord)xa );
sewardjb4112022007-11-09 22:49:28 +00002692 }
2693}
2694
sewardjf98e1c02008-10-25 16:22:41 +00002695static SO* mb_pop_SO_for_sem ( void* sem ) {
2696 UWord keyW;
sewardjb4112022007-11-09 22:49:28 +00002697 XArray* xa;
sewardjf98e1c02008-10-25 16:22:41 +00002698 SO* so;
2699 map_sem_to_SO_stack_INIT();
2700 if (VG_(lookupFM)( map_sem_to_SO_stack,
2701 &keyW, (UWord*)&xa, (UWord)sem )) {
sewardjb4112022007-11-09 22:49:28 +00002702 /* xa is the stack for this semaphore. */
sewardjf98e1c02008-10-25 16:22:41 +00002703 Word sz;
2704 tl_assert(keyW == (UWord)sem);
2705 sz = VG_(sizeXA)( xa );
sewardjb4112022007-11-09 22:49:28 +00002706 tl_assert(sz >= 0);
2707 if (sz == 0)
2708 return NULL; /* odd, the stack is empty */
sewardjf98e1c02008-10-25 16:22:41 +00002709 so = *(SO**)VG_(indexXA)( xa, sz-1 );
2710 tl_assert(so);
sewardjb4112022007-11-09 22:49:28 +00002711 VG_(dropTailXA)( xa, 1 );
sewardjf98e1c02008-10-25 16:22:41 +00002712 return so;
sewardjb4112022007-11-09 22:49:28 +00002713 } else {
2714 /* hmm, that's odd. No stack for this semaphore. */
2715 return NULL;
2716 }
2717}
2718
sewardj11e352f2007-11-30 11:11:02 +00002719static void evh__HG_POSIX_SEM_DESTROY_PRE ( ThreadId tid, void* sem )
sewardjb4112022007-11-09 22:49:28 +00002720{
sewardjf98e1c02008-10-25 16:22:41 +00002721 UWord keyW, valW;
2722 SO* so;
sewardjb4112022007-11-09 22:49:28 +00002723
sewardjb4112022007-11-09 22:49:28 +00002724 if (SHOW_EVENTS >= 1)
sewardj11e352f2007-11-30 11:11:02 +00002725 VG_(printf)("evh__HG_POSIX_SEM_DESTROY_PRE(ctid=%d, sem=%p)\n",
sewardjb4112022007-11-09 22:49:28 +00002726 (Int)tid, (void*)sem );
2727
sewardjf98e1c02008-10-25 16:22:41 +00002728 map_sem_to_SO_stack_INIT();
sewardjb4112022007-11-09 22:49:28 +00002729
sewardjf98e1c02008-10-25 16:22:41 +00002730 /* Empty out the semaphore's SO stack. This way of doing it is
2731 stupid, but at least it's easy. */
2732 while (1) {
2733 so = mb_pop_SO_for_sem( sem );
2734 if (!so) break;
2735 libhb_so_dealloc(so);
2736 }
2737
2738 if (VG_(delFromFM)( map_sem_to_SO_stack, &keyW, &valW, (UWord)sem )) {
2739 XArray* xa = (XArray*)valW;
2740 tl_assert(keyW == (UWord)sem);
2741 tl_assert(xa);
2742 tl_assert(VG_(sizeXA)(xa) == 0); /* preceding loop just emptied it */
2743 VG_(deleteXA)(xa);
2744 }
sewardjb4112022007-11-09 22:49:28 +00002745}
2746
sewardj11e352f2007-11-30 11:11:02 +00002747static
2748void evh__HG_POSIX_SEM_INIT_POST ( ThreadId tid, void* sem, UWord value )
2749{
sewardjf98e1c02008-10-25 16:22:41 +00002750 SO* so;
2751 Thread* thr;
sewardj11e352f2007-11-30 11:11:02 +00002752
2753 if (SHOW_EVENTS >= 1)
2754 VG_(printf)("evh__HG_POSIX_SEM_INIT_POST(ctid=%d, sem=%p, value=%lu)\n",
2755 (Int)tid, (void*)sem, value );
2756
sewardjf98e1c02008-10-25 16:22:41 +00002757 thr = map_threads_maybe_lookup( tid );
2758 tl_assert(thr); /* cannot fail - Thread* must already exist */
sewardj11e352f2007-11-30 11:11:02 +00002759
sewardjf98e1c02008-10-25 16:22:41 +00002760 /* Empty out the semaphore's SO stack. This way of doing it is
2761 stupid, but at least it's easy. */
2762 while (1) {
2763 so = mb_pop_SO_for_sem( sem );
2764 if (!so) break;
2765 libhb_so_dealloc(so);
2766 }
sewardj11e352f2007-11-30 11:11:02 +00002767
sewardjf98e1c02008-10-25 16:22:41 +00002768 /* If we don't do this check, the following while loop runs us out
2769 of memory for stupid initial values of 'value'. */
2770 if (value > 10000) {
2771 HG_(record_error_Misc)(
2772 thr, "sem_init: initial value exceeds 10000; using 10000" );
2773 value = 10000;
2774 }
sewardj11e352f2007-11-30 11:11:02 +00002775
sewardjf98e1c02008-10-25 16:22:41 +00002776 /* Now create 'valid' new SOs for the thread, do a strong send to
2777 each of them, and push them all on the stack. */
2778 for (; value > 0; value--) {
2779 Thr* hbthr = thr->hbthr;
2780 tl_assert(hbthr);
sewardj11e352f2007-11-30 11:11:02 +00002781
sewardjf98e1c02008-10-25 16:22:41 +00002782 so = libhb_so_alloc();
2783 libhb_so_send( hbthr, so, True/*strong send*/ );
2784 push_SO_for_sem( sem, so );
sewardj11e352f2007-11-30 11:11:02 +00002785 }
2786}
2787
2788static void evh__HG_POSIX_SEM_POST_PRE ( ThreadId tid, void* sem )
sewardjb4112022007-11-09 22:49:28 +00002789{
sewardjf98e1c02008-10-25 16:22:41 +00002790 /* 'tid' has posted on 'sem'. Create a new SO, do a strong send to
2791 it (iow, write our VC into it, then tick ours), and push the SO
2792 on on a stack of SOs associated with 'sem'. This is later used
2793 by other thread(s) which successfully exit from a sem_wait on
2794 the same sem; by doing a strong recv from SOs popped of the
2795 stack, they acquire dependencies on the posting thread
2796 segment(s). */
sewardjb4112022007-11-09 22:49:28 +00002797
sewardjf98e1c02008-10-25 16:22:41 +00002798 Thread* thr;
2799 SO* so;
2800 Thr* hbthr;
sewardjb4112022007-11-09 22:49:28 +00002801
2802 if (SHOW_EVENTS >= 1)
sewardj11e352f2007-11-30 11:11:02 +00002803 VG_(printf)("evh__HG_POSIX_SEM_POST_PRE(ctid=%d, sem=%p)\n",
sewardjb4112022007-11-09 22:49:28 +00002804 (Int)tid, (void*)sem );
2805
2806 thr = map_threads_maybe_lookup( tid );
2807 tl_assert(thr); /* cannot fail - Thread* must already exist */
2808
2809 // error-if: sem is bogus
2810
sewardjf98e1c02008-10-25 16:22:41 +00002811 hbthr = thr->hbthr;
2812 tl_assert(hbthr);
sewardjb4112022007-11-09 22:49:28 +00002813
sewardjf98e1c02008-10-25 16:22:41 +00002814 so = libhb_so_alloc();
2815 libhb_so_send( hbthr, so, True/*strong send*/ );
2816 push_SO_for_sem( sem, so );
sewardjb4112022007-11-09 22:49:28 +00002817}
2818
sewardj11e352f2007-11-30 11:11:02 +00002819static void evh__HG_POSIX_SEM_WAIT_POST ( ThreadId tid, void* sem )
sewardjb4112022007-11-09 22:49:28 +00002820{
sewardjf98e1c02008-10-25 16:22:41 +00002821 /* A sem_wait(sem) completed successfully. Pop the posting-SO for
2822 the 'sem' from this semaphore's SO-stack, and do a strong recv
2823 from it. This creates a dependency back to one of the post-ers
2824 for the semaphore. */
sewardjb4112022007-11-09 22:49:28 +00002825
sewardjf98e1c02008-10-25 16:22:41 +00002826 Thread* thr;
2827 SO* so;
2828 Thr* hbthr;
sewardjb4112022007-11-09 22:49:28 +00002829
2830 if (SHOW_EVENTS >= 1)
sewardj11e352f2007-11-30 11:11:02 +00002831 VG_(printf)("evh__HG_POSIX_SEM_WAIT_POST(ctid=%d, sem=%p)\n",
sewardjb4112022007-11-09 22:49:28 +00002832 (Int)tid, (void*)sem );
2833
2834 thr = map_threads_maybe_lookup( tid );
2835 tl_assert(thr); /* cannot fail - Thread* must already exist */
2836
2837 // error-if: sem is bogus
2838
sewardjf98e1c02008-10-25 16:22:41 +00002839 so = mb_pop_SO_for_sem( sem );
sewardjb4112022007-11-09 22:49:28 +00002840
sewardjf98e1c02008-10-25 16:22:41 +00002841 if (so) {
2842 hbthr = thr->hbthr;
2843 tl_assert(hbthr);
2844
2845 libhb_so_recv( hbthr, so, True/*strong recv*/ );
2846 libhb_so_dealloc(so);
2847 } else {
2848 /* Hmm. How can a wait on 'sem' succeed if nobody posted to it?
2849 If this happened it would surely be a bug in the threads
2850 library. */
2851 HG_(record_error_Misc)(
2852 thr, "Bug in libpthread: sem_wait succeeded on"
2853 " semaphore without prior sem_post");
sewardjb4112022007-11-09 22:49:28 +00002854 }
2855}
2856
2857
sewardj9f569b72008-11-13 13:33:09 +00002858/* -------------------------------------------------------- */
2859/* -------------- events to do with barriers -------------- */
2860/* -------------------------------------------------------- */
2861
2862typedef
2863 struct {
2864 Bool initted; /* has it yet been initted by guest? */
sewardj406bac82010-03-03 23:03:40 +00002865 Bool resizable; /* is resizing allowed? */
sewardj9f569b72008-11-13 13:33:09 +00002866 UWord size; /* declared size */
2867 XArray* waiting; /* XA of Thread*. # present is 0 .. .size */
2868 }
2869 Bar;
2870
2871static Bar* new_Bar ( void ) {
2872 Bar* bar = HG_(zalloc)( "hg.nB.1 (new_Bar)", sizeof(Bar) );
sewardj9f569b72008-11-13 13:33:09 +00002873 /* all fields are zero */
2874 tl_assert(bar->initted == False);
2875 return bar;
2876}
2877
2878static void delete_Bar ( Bar* bar ) {
2879 tl_assert(bar);
2880 if (bar->waiting)
2881 VG_(deleteXA)(bar->waiting);
2882 HG_(free)(bar);
2883}
2884
2885/* A mapping which stores auxiliary data for barriers. */
2886
2887/* pthread_barrier_t* -> Bar* */
2888static WordFM* map_barrier_to_Bar = NULL;
2889
2890static void map_barrier_to_Bar_INIT ( void ) {
2891 if (UNLIKELY(map_barrier_to_Bar == NULL)) {
2892 map_barrier_to_Bar = VG_(newFM)( HG_(zalloc),
2893 "hg.mbtBI.1", HG_(free), NULL );
sewardj9f569b72008-11-13 13:33:09 +00002894 }
2895}
2896
2897static Bar* map_barrier_to_Bar_lookup_or_alloc ( void* barrier ) {
2898 UWord key, val;
2899 map_barrier_to_Bar_INIT();
2900 if (VG_(lookupFM)( map_barrier_to_Bar, &key, &val, (UWord)barrier )) {
2901 tl_assert(key == (UWord)barrier);
2902 return (Bar*)val;
2903 } else {
2904 Bar* bar = new_Bar();
2905 VG_(addToFM)( map_barrier_to_Bar, (UWord)barrier, (UWord)bar );
2906 return bar;
2907 }
2908}
2909
2910static void map_barrier_to_Bar_delete ( void* barrier ) {
2911 UWord keyW, valW;
2912 map_barrier_to_Bar_INIT();
2913 if (VG_(delFromFM)( map_barrier_to_Bar, &keyW, &valW, (UWord)barrier )) {
2914 Bar* bar = (Bar*)valW;
2915 tl_assert(keyW == (UWord)barrier);
2916 delete_Bar(bar);
2917 }
2918}
2919
2920
2921static void evh__HG_PTHREAD_BARRIER_INIT_PRE ( ThreadId tid,
2922 void* barrier,
sewardj406bac82010-03-03 23:03:40 +00002923 UWord count,
2924 UWord resizable )
sewardj9f569b72008-11-13 13:33:09 +00002925{
2926 Thread* thr;
2927 Bar* bar;
2928
2929 if (SHOW_EVENTS >= 1)
2930 VG_(printf)("evh__HG_PTHREAD_BARRIER_INIT_PRE"
sewardj406bac82010-03-03 23:03:40 +00002931 "(tid=%d, barrier=%p, count=%lu, resizable=%lu)\n",
2932 (Int)tid, (void*)barrier, count, resizable );
sewardj9f569b72008-11-13 13:33:09 +00002933
2934 thr = map_threads_maybe_lookup( tid );
2935 tl_assert(thr); /* cannot fail - Thread* must already exist */
2936
2937 if (count == 0) {
2938 HG_(record_error_Misc)(
2939 thr, "pthread_barrier_init: 'count' argument is zero"
2940 );
2941 }
2942
sewardj406bac82010-03-03 23:03:40 +00002943 if (resizable != 0 && resizable != 1) {
2944 HG_(record_error_Misc)(
2945 thr, "pthread_barrier_init: invalid 'resizable' argument"
2946 );
2947 }
2948
sewardj9f569b72008-11-13 13:33:09 +00002949 bar = map_barrier_to_Bar_lookup_or_alloc(barrier);
2950 tl_assert(bar);
2951
2952 if (bar->initted) {
2953 HG_(record_error_Misc)(
2954 thr, "pthread_barrier_init: barrier is already initialised"
2955 );
2956 }
2957
2958 if (bar->waiting && VG_(sizeXA)(bar->waiting) > 0) {
2959 tl_assert(bar->initted);
2960 HG_(record_error_Misc)(
sewardj553655c2008-11-14 19:41:19 +00002961 thr, "pthread_barrier_init: threads are waiting at barrier"
sewardj9f569b72008-11-13 13:33:09 +00002962 );
2963 VG_(dropTailXA)(bar->waiting, VG_(sizeXA)(bar->waiting));
2964 }
2965 if (!bar->waiting) {
2966 bar->waiting = VG_(newXA)( HG_(zalloc), "hg.eHPBIP.1", HG_(free),
2967 sizeof(Thread*) );
2968 }
2969
sewardj9f569b72008-11-13 13:33:09 +00002970 tl_assert(VG_(sizeXA)(bar->waiting) == 0);
sewardj406bac82010-03-03 23:03:40 +00002971 bar->initted = True;
2972 bar->resizable = resizable == 1 ? True : False;
2973 bar->size = count;
sewardj9f569b72008-11-13 13:33:09 +00002974}
2975
2976
2977static void evh__HG_PTHREAD_BARRIER_DESTROY_PRE ( ThreadId tid,
2978 void* barrier )
2979{
sewardj553655c2008-11-14 19:41:19 +00002980 Thread* thr;
2981 Bar* bar;
2982
sewardj9f569b72008-11-13 13:33:09 +00002983 /* Deal with destroy events. The only purpose is to free storage
2984 associated with the barrier, so as to avoid any possible
2985 resource leaks. */
2986 if (SHOW_EVENTS >= 1)
2987 VG_(printf)("evh__HG_PTHREAD_BARRIER_DESTROY_PRE"
2988 "(tid=%d, barrier=%p)\n",
2989 (Int)tid, (void*)barrier );
2990
sewardj553655c2008-11-14 19:41:19 +00002991 thr = map_threads_maybe_lookup( tid );
2992 tl_assert(thr); /* cannot fail - Thread* must already exist */
2993
2994 bar = map_barrier_to_Bar_lookup_or_alloc(barrier);
2995 tl_assert(bar);
2996
2997 if (!bar->initted) {
2998 HG_(record_error_Misc)(
2999 thr, "pthread_barrier_destroy: barrier was never initialised"
3000 );
3001 }
3002
3003 if (bar->initted && bar->waiting && VG_(sizeXA)(bar->waiting) > 0) {
3004 HG_(record_error_Misc)(
3005 thr, "pthread_barrier_destroy: threads are waiting at barrier"
3006 );
3007 }
3008
sewardj9f569b72008-11-13 13:33:09 +00003009 /* Maybe we shouldn't do this; just let it persist, so that when it
3010 is reinitialised we don't need to do any dynamic memory
3011 allocation? The downside is a potentially unlimited space leak,
3012 if the client creates (in turn) a large number of barriers all
3013 at different locations. Note that if we do later move to the
3014 don't-delete-it scheme, we need to mark the barrier as
3015 uninitialised again since otherwise a later _init call will
sewardj553655c2008-11-14 19:41:19 +00003016 elicit a duplicate-init error. */
sewardj9f569b72008-11-13 13:33:09 +00003017 map_barrier_to_Bar_delete( barrier );
3018}
3019
3020
sewardj406bac82010-03-03 23:03:40 +00003021/* All the threads have arrived. Now do the Interesting Bit. Get a
3022 new synchronisation object and do a weak send to it from all the
3023 participating threads. This makes its vector clocks be the join of
3024 all the individual threads' vector clocks. Then do a strong
3025 receive from it back to all threads, so that their VCs are a copy
3026 of it (hence are all equal to the join of their original VCs.) */
3027static void do_barrier_cross_sync_and_empty ( Bar* bar )
3028{
3029 /* XXX check bar->waiting has no duplicates */
3030 UWord i;
3031 SO* so = libhb_so_alloc();
3032
3033 tl_assert(bar->waiting);
3034 tl_assert(VG_(sizeXA)(bar->waiting) == bar->size);
3035
3036 /* compute the join ... */
3037 for (i = 0; i < bar->size; i++) {
3038 Thread* t = *(Thread**)VG_(indexXA)(bar->waiting, i);
3039 Thr* hbthr = t->hbthr;
3040 libhb_so_send( hbthr, so, False/*weak send*/ );
3041 }
3042 /* ... and distribute to all threads */
3043 for (i = 0; i < bar->size; i++) {
3044 Thread* t = *(Thread**)VG_(indexXA)(bar->waiting, i);
3045 Thr* hbthr = t->hbthr;
3046 libhb_so_recv( hbthr, so, True/*strong recv*/ );
3047 }
3048
3049 /* finally, we must empty out the waiting vector */
3050 VG_(dropTailXA)(bar->waiting, VG_(sizeXA)(bar->waiting));
3051
3052 /* and we don't need this any more. Perhaps a stack-allocated
3053 SO would be better? */
3054 libhb_so_dealloc(so);
3055}
3056
3057
sewardj9f569b72008-11-13 13:33:09 +00003058static void evh__HG_PTHREAD_BARRIER_WAIT_PRE ( ThreadId tid,
3059 void* barrier )
3060{
sewardj1c466b72008-11-19 11:52:14 +00003061 /* This function gets called after a client thread calls
3062 pthread_barrier_wait but before it arrives at the real
3063 pthread_barrier_wait.
3064
3065 Why is the following correct? It's a bit subtle.
3066
3067 If this is not the last thread arriving at the barrier, we simply
3068 note its presence and return. Because valgrind (at least as of
3069 Nov 08) is single threaded, we are guaranteed safe from any race
3070 conditions when in this function -- no other client threads are
3071 running.
3072
3073 If this is the last thread, then we are again the only running
3074 thread. All the other threads will have either arrived at the
3075 real pthread_barrier_wait or are on their way to it, but in any
3076 case are guaranteed not to be able to move past it, because this
3077 thread is currently in this function and so has not yet arrived
3078 at the real pthread_barrier_wait. That means that:
3079
3080 1. While we are in this function, none of the other threads
3081 waiting at the barrier can move past it.
3082
3083 2. When this function returns (and simulated execution resumes),
3084 this thread and all other waiting threads will be able to move
3085 past the real barrier.
3086
3087 Because of this, it is now safe to update the vector clocks of
3088 all threads, to represent the fact that they all arrived at the
3089 barrier and have all moved on. There is no danger of any
3090 complications to do with some threads leaving the barrier and
3091 racing back round to the front, whilst others are still leaving
3092 (which is the primary source of complication in correct handling/
3093 implementation of barriers). That can't happen because we update
3094 here our data structures so as to indicate that the threads have
3095 passed the barrier, even though, as per (2) above, they are
3096 guaranteed not to pass the barrier until we return.
3097
3098 This relies crucially on Valgrind being single threaded. If that
3099 changes, this will need to be reconsidered.
3100 */
sewardj9f569b72008-11-13 13:33:09 +00003101 Thread* thr;
3102 Bar* bar;
sewardj406bac82010-03-03 23:03:40 +00003103 UWord present;
sewardj9f569b72008-11-13 13:33:09 +00003104
3105 if (SHOW_EVENTS >= 1)
3106 VG_(printf)("evh__HG_PTHREAD_BARRIER_WAIT_PRE"
3107 "(tid=%d, barrier=%p)\n",
3108 (Int)tid, (void*)barrier );
3109
3110 thr = map_threads_maybe_lookup( tid );
3111 tl_assert(thr); /* cannot fail - Thread* must already exist */
3112
3113 bar = map_barrier_to_Bar_lookup_or_alloc(barrier);
3114 tl_assert(bar);
3115
3116 if (!bar->initted) {
3117 HG_(record_error_Misc)(
3118 thr, "pthread_barrier_wait: barrier is uninitialised"
3119 );
3120 return; /* client is broken .. avoid assertions below */
3121 }
3122
3123 /* guaranteed by _INIT_PRE above */
3124 tl_assert(bar->size > 0);
3125 tl_assert(bar->waiting);
3126
3127 VG_(addToXA)( bar->waiting, &thr );
3128
3129 /* guaranteed by this function */
3130 present = VG_(sizeXA)(bar->waiting);
3131 tl_assert(present > 0 && present <= bar->size);
3132
3133 if (present < bar->size)
3134 return;
3135
sewardj406bac82010-03-03 23:03:40 +00003136 do_barrier_cross_sync_and_empty(bar);
3137}
sewardj9f569b72008-11-13 13:33:09 +00003138
sewardj9f569b72008-11-13 13:33:09 +00003139
sewardj406bac82010-03-03 23:03:40 +00003140static void evh__HG_PTHREAD_BARRIER_RESIZE_PRE ( ThreadId tid,
3141 void* barrier,
3142 UWord newcount )
3143{
3144 Thread* thr;
3145 Bar* bar;
3146 UWord present;
3147
3148 if (SHOW_EVENTS >= 1)
3149 VG_(printf)("evh__HG_PTHREAD_BARRIER_RESIZE_PRE"
3150 "(tid=%d, barrier=%p, newcount=%lu)\n",
3151 (Int)tid, (void*)barrier, newcount );
3152
3153 thr = map_threads_maybe_lookup( tid );
3154 tl_assert(thr); /* cannot fail - Thread* must already exist */
3155
3156 bar = map_barrier_to_Bar_lookup_or_alloc(barrier);
3157 tl_assert(bar);
3158
3159 if (!bar->initted) {
3160 HG_(record_error_Misc)(
3161 thr, "pthread_barrier_resize: barrier is uninitialised"
3162 );
3163 return; /* client is broken .. avoid assertions below */
3164 }
3165
3166 if (!bar->resizable) {
3167 HG_(record_error_Misc)(
3168 thr, "pthread_barrier_resize: barrier is may not be resized"
3169 );
3170 return; /* client is broken .. avoid assertions below */
3171 }
3172
3173 if (newcount == 0) {
3174 HG_(record_error_Misc)(
3175 thr, "pthread_barrier_resize: 'newcount' argument is zero"
3176 );
3177 return; /* client is broken .. avoid assertions below */
3178 }
3179
3180 /* guaranteed by _INIT_PRE above */
3181 tl_assert(bar->size > 0);
sewardj9f569b72008-11-13 13:33:09 +00003182 tl_assert(bar->waiting);
sewardj406bac82010-03-03 23:03:40 +00003183 /* Guaranteed by this fn */
3184 tl_assert(newcount > 0);
sewardj9f569b72008-11-13 13:33:09 +00003185
sewardj406bac82010-03-03 23:03:40 +00003186 if (newcount >= bar->size) {
3187 /* Increasing the capacity. There's no possibility of threads
3188 moving on from the barrier in this situation, so just note
3189 the fact and do nothing more. */
3190 bar->size = newcount;
3191 } else {
3192 /* Decreasing the capacity. If we decrease it to be equal or
3193 below the number of waiting threads, they will now move past
3194 the barrier, so need to mess with dep edges in the same way
3195 as if the barrier had filled up normally. */
3196 present = VG_(sizeXA)(bar->waiting);
3197 tl_assert(present >= 0 && present <= bar->size);
3198 if (newcount <= present) {
3199 bar->size = present; /* keep the cross_sync call happy */
3200 do_barrier_cross_sync_and_empty(bar);
3201 }
3202 bar->size = newcount;
sewardj9f569b72008-11-13 13:33:09 +00003203 }
sewardj9f569b72008-11-13 13:33:09 +00003204}
3205
3206
sewardjed2e72e2009-08-14 11:08:24 +00003207/* ----------------------------------------------------- */
3208/* ----- events to do with user-specified HB edges ----- */
3209/* ----------------------------------------------------- */
3210
3211/* A mapping from arbitrary UWord tag to the SO associated with it.
3212 The UWord tags are meaningless to us, interpreted only by the
3213 user. */
3214
3215
3216
3217/* UWord -> SO* */
3218static WordFM* map_usertag_to_SO = NULL;
3219
3220static void map_usertag_to_SO_INIT ( void ) {
3221 if (UNLIKELY(map_usertag_to_SO == NULL)) {
3222 map_usertag_to_SO = VG_(newFM)( HG_(zalloc),
3223 "hg.mutS.1", HG_(free), NULL );
sewardjed2e72e2009-08-14 11:08:24 +00003224 }
3225}
3226
3227static SO* map_usertag_to_SO_lookup_or_alloc ( UWord usertag ) {
3228 UWord key, val;
3229 map_usertag_to_SO_INIT();
3230 if (VG_(lookupFM)( map_usertag_to_SO, &key, &val, usertag )) {
3231 tl_assert(key == (UWord)usertag);
3232 return (SO*)val;
3233 } else {
3234 SO* so = libhb_so_alloc();
3235 VG_(addToFM)( map_usertag_to_SO, usertag, (UWord)so );
3236 return so;
3237 }
3238}
3239
sewardj6015d0e2011-03-11 19:10:48 +00003240static void map_usertag_to_SO_delete ( UWord usertag ) {
3241 UWord keyW, valW;
3242 map_usertag_to_SO_INIT();
3243 if (VG_(delFromFM)( map_usertag_to_SO, &keyW, &valW, usertag )) {
3244 SO* so = (SO*)valW;
3245 tl_assert(keyW == usertag);
3246 tl_assert(so);
3247 libhb_so_dealloc(so);
3248 }
3249}
sewardjed2e72e2009-08-14 11:08:24 +00003250
3251
3252static
3253void evh__HG_USERSO_SEND_PRE ( ThreadId tid, UWord usertag )
3254{
3255 /* TID is just about to notionally sent a message on a notional
3256 abstract synchronisation object whose identity is given by
3257 USERTAG. Bind USERTAG to a real SO if it is not already so
sewardj8c50d3c2011-03-11 18:38:12 +00003258 bound, and do a 'weak send' on the SO. This joins the vector
3259 clocks from this thread into any vector clocks already present
3260 in the SO. The resulting SO vector clocks are later used by
sewardjed2e72e2009-08-14 11:08:24 +00003261 other thread(s) which successfully 'receive' from the SO,
sewardj8c50d3c2011-03-11 18:38:12 +00003262 thereby acquiring a dependency on all the events that have
3263 previously signalled on this SO. */
sewardjed2e72e2009-08-14 11:08:24 +00003264 Thread* thr;
3265 SO* so;
3266
3267 if (SHOW_EVENTS >= 1)
3268 VG_(printf)("evh__HG_USERSO_SEND_PRE(ctid=%d, usertag=%#lx)\n",
3269 (Int)tid, usertag );
3270
3271 thr = map_threads_maybe_lookup( tid );
3272 tl_assert(thr); /* cannot fail - Thread* must already exist */
3273
3274 so = map_usertag_to_SO_lookup_or_alloc( usertag );
3275 tl_assert(so);
3276
sewardj8c50d3c2011-03-11 18:38:12 +00003277 libhb_so_send( thr->hbthr, so, False/*!strong_send*/ );
sewardjed2e72e2009-08-14 11:08:24 +00003278}
3279
3280static
3281void evh__HG_USERSO_RECV_POST ( ThreadId tid, UWord usertag )
3282{
3283 /* TID has just notionally received a message from a notional
3284 abstract synchronisation object whose identity is given by
3285 USERTAG. Bind USERTAG to a real SO if it is not already so
3286 bound. If the SO has at some point in the past been 'sent' on,
3287 to a 'strong receive' on it, thereby acquiring a dependency on
3288 the sender. */
3289 Thread* thr;
3290 SO* so;
3291
3292 if (SHOW_EVENTS >= 1)
3293 VG_(printf)("evh__HG_USERSO_RECV_POST(ctid=%d, usertag=%#lx)\n",
3294 (Int)tid, usertag );
3295
3296 thr = map_threads_maybe_lookup( tid );
3297 tl_assert(thr); /* cannot fail - Thread* must already exist */
3298
3299 so = map_usertag_to_SO_lookup_or_alloc( usertag );
3300 tl_assert(so);
3301
3302 /* Acquire a dependency on it. If the SO has never so far been
3303 sent on, then libhb_so_recv will do nothing. So we're safe
3304 regardless of SO's history. */
3305 libhb_so_recv( thr->hbthr, so, True/*strong_recv*/ );
3306}
3307
sewardj6015d0e2011-03-11 19:10:48 +00003308static
3309void evh__HG_USERSO_FORGET_ALL ( ThreadId tid, UWord usertag )
3310{
3311 /* TID declares that any happens-before edges notionally stored in
3312 USERTAG can be deleted. If (as would normally be the case) a
3313 SO is associated with USERTAG, then the assocation is removed
3314 and all resources associated with SO are freed. Importantly,
3315 that frees up any VTSs stored in SO. */
3316 if (SHOW_EVENTS >= 1)
3317 VG_(printf)("evh__HG_USERSO_FORGET_ALL(ctid=%d, usertag=%#lx)\n",
3318 (Int)tid, usertag );
3319
3320 map_usertag_to_SO_delete( usertag );
3321}
3322
sewardjed2e72e2009-08-14 11:08:24 +00003323
sewardjb4112022007-11-09 22:49:28 +00003324/*--------------------------------------------------------------*/
3325/*--- Lock acquisition order monitoring ---*/
3326/*--------------------------------------------------------------*/
3327
3328/* FIXME: here are some optimisations still to do in
3329 laog__pre_thread_acquires_lock.
3330
3331 The graph is structured so that if L1 --*--> L2 then L1 must be
3332 acquired before L2.
3333
3334 The common case is that some thread T holds (eg) L1 L2 and L3 and
3335 is repeatedly acquiring and releasing Ln, and there is no ordering
3336 error in what it is doing. Hence it repeatly:
3337
3338 (1) searches laog to see if Ln --*--> {L1,L2,L3}, which always
3339 produces the answer No (because there is no error).
3340
3341 (2) adds edges {L1,L2,L3} --> Ln to laog, which are already present
3342 (because they already got added the first time T acquired Ln).
3343
3344 Hence cache these two events:
3345
3346 (1) Cache result of the query from last time. Invalidate the cache
3347 any time any edges are added to or deleted from laog.
3348
3349 (2) Cache these add-edge requests and ignore them if said edges
3350 have already been added to laog. Invalidate the cache any time
3351 any edges are deleted from laog.
3352*/
3353
3354typedef
3355 struct {
3356 WordSetID inns; /* in univ_laog */
3357 WordSetID outs; /* in univ_laog */
3358 }
3359 LAOGLinks;
3360
3361/* lock order acquisition graph */
3362static WordFM* laog = NULL; /* WordFM Lock* LAOGLinks* */
3363
3364/* EXPOSITION ONLY: for each edge in 'laog', record the two places
3365 where that edge was created, so that we can show the user later if
3366 we need to. */
3367typedef
3368 struct {
3369 Addr src_ga; /* Lock guest addresses for */
3370 Addr dst_ga; /* src/dst of the edge */
3371 ExeContext* src_ec; /* And corresponding places where that */
3372 ExeContext* dst_ec; /* ordering was established */
3373 }
3374 LAOGLinkExposition;
3375
sewardj250ec2e2008-02-15 22:02:30 +00003376static Word cmp_LAOGLinkExposition ( UWord llx1W, UWord llx2W ) {
sewardjb4112022007-11-09 22:49:28 +00003377 /* Compare LAOGLinkExposition*s by (src_ga,dst_ga) field pair. */
3378 LAOGLinkExposition* llx1 = (LAOGLinkExposition*)llx1W;
3379 LAOGLinkExposition* llx2 = (LAOGLinkExposition*)llx2W;
3380 if (llx1->src_ga < llx2->src_ga) return -1;
3381 if (llx1->src_ga > llx2->src_ga) return 1;
3382 if (llx1->dst_ga < llx2->dst_ga) return -1;
3383 if (llx1->dst_ga > llx2->dst_ga) return 1;
3384 return 0;
3385}
3386
3387static WordFM* laog_exposition = NULL; /* WordFM LAOGLinkExposition* NULL */
3388/* end EXPOSITION ONLY */
3389
3390
sewardja65db102009-01-26 10:45:16 +00003391__attribute__((noinline))
3392static void laog__init ( void )
3393{
3394 tl_assert(!laog);
3395 tl_assert(!laog_exposition);
sewardjc1fb9d22011-02-28 09:03:44 +00003396 tl_assert(HG_(clo_track_lockorders));
sewardja65db102009-01-26 10:45:16 +00003397
3398 laog = VG_(newFM)( HG_(zalloc), "hg.laog__init.1",
3399 HG_(free), NULL/*unboxedcmp*/ );
3400
3401 laog_exposition = VG_(newFM)( HG_(zalloc), "hg.laog__init.2", HG_(free),
3402 cmp_LAOGLinkExposition );
sewardja65db102009-01-26 10:45:16 +00003403}
3404
florian6bf37262012-10-21 03:23:36 +00003405static void laog__show ( const HChar* who ) {
3406 UWord i, ws_size;
sewardj250ec2e2008-02-15 22:02:30 +00003407 UWord* ws_words;
sewardjb4112022007-11-09 22:49:28 +00003408 Lock* me;
3409 LAOGLinks* links;
3410 VG_(printf)("laog (requested by %s) {\n", who);
sewardj896f6f92008-08-19 08:38:52 +00003411 VG_(initIterFM)( laog );
sewardjb4112022007-11-09 22:49:28 +00003412 me = NULL;
3413 links = NULL;
florian6bf37262012-10-21 03:23:36 +00003414 while (VG_(nextIterFM)( laog, (UWord*)&me,
3415 (UWord*)&links )) {
sewardjb4112022007-11-09 22:49:28 +00003416 tl_assert(me);
3417 tl_assert(links);
3418 VG_(printf)(" node %p:\n", me);
3419 HG_(getPayloadWS)( &ws_words, &ws_size, univ_laog, links->inns );
3420 for (i = 0; i < ws_size; i++)
barta0b6b2c2008-07-07 06:49:24 +00003421 VG_(printf)(" inn %#lx\n", ws_words[i] );
sewardjb4112022007-11-09 22:49:28 +00003422 HG_(getPayloadWS)( &ws_words, &ws_size, univ_laog, links->outs );
3423 for (i = 0; i < ws_size; i++)
barta0b6b2c2008-07-07 06:49:24 +00003424 VG_(printf)(" out %#lx\n", ws_words[i] );
sewardjb4112022007-11-09 22:49:28 +00003425 me = NULL;
3426 links = NULL;
3427 }
sewardj896f6f92008-08-19 08:38:52 +00003428 VG_(doneIterFM)( laog );
sewardjb4112022007-11-09 22:49:28 +00003429 VG_(printf)("}\n");
3430}
3431
sewardj866c80c2011-10-22 19:29:51 +00003432static void univ_laog_do_GC ( void ) {
3433 Word i;
3434 LAOGLinks* links;
3435 Word seen = 0;
3436 Int prev_next_gc_univ_laog = next_gc_univ_laog;
3437 const UWord univ_laog_cardinality = HG_(cardinalityWSU)( univ_laog);
3438
3439 Bool *univ_laog_seen = HG_(zalloc) ( "hg.gc_univ_laog.1",
3440 (Int) univ_laog_cardinality
3441 * sizeof(Bool) );
3442 // univ_laog_seen[*] set to 0 (False) by zalloc.
3443
sewardj866c80c2011-10-22 19:29:51 +00003444 VG_(initIterFM)( laog );
3445 links = NULL;
3446 while (VG_(nextIterFM)( laog, NULL, (UWord*)&links )) {
3447 tl_assert(links);
3448 tl_assert(links->inns >= 0 && links->inns < univ_laog_cardinality);
3449 univ_laog_seen[links->inns] = True;
3450 tl_assert(links->outs >= 0 && links->outs < univ_laog_cardinality);
3451 univ_laog_seen[links->outs] = True;
3452 links = NULL;
3453 }
3454 VG_(doneIterFM)( laog );
3455
3456 for (i = 0; i < (Int)univ_laog_cardinality; i++) {
3457 if (univ_laog_seen[i])
3458 seen++;
3459 else
3460 HG_(dieWS) ( univ_laog, (WordSet)i );
3461 }
3462
3463 HG_(free) (univ_laog_seen);
3464
3465 // We need to decide the value of the next_gc.
3466 // 3 solutions were looked at:
3467 // Sol 1: garbage collect at seen * 2
3468 // This solution was a lot slower, probably because we both do a lot of
3469 // garbage collection and do not keep long enough laog WV that will become
3470 // useful again very soon.
3471 // Sol 2: garbage collect at a percentage increase of the current cardinality
3472 // (with a min increase of 1)
3473 // Trials on a small test program with 1%, 5% and 10% increase was done.
3474 // 1% is slightly faster than 5%, which is slightly slower than 10%.
3475 // However, on a big application, this caused the memory to be exhausted,
3476 // as even a 1% increase of size at each gc becomes a lot, when many gc
3477 // are done.
3478 // Sol 3: always garbage collect at current cardinality + 1.
3479 // This solution was the fastest of the 3 solutions, and caused no memory
3480 // exhaustion in the big application.
3481 //
3482 // With regards to cost introduced by gc: on the t2t perf test (doing only
3483 // lock/unlock operations), t2t 50 10 2 was about 25% faster than the
3484 // version with garbage collection. With t2t 50 20 2, my machine started
3485 // to page out, and so the garbage collected version was much faster.
3486 // On smaller lock sets (e.g. t2t 20 5 2, giving about 100 locks), the
3487 // difference performance is insignificant (~ 0.1 s).
3488 // Of course, it might be that real life programs are not well represented
3489 // by t2t.
3490
3491 // If ever we want to have a more sophisticated control
3492 // (e.g. clo options to control the percentage increase or fixed increased),
3493 // we should do it here, eg.
3494 // next_gc_univ_laog = prev_next_gc_univ_laog + VG_(clo_laog_gc_fixed);
3495 // Currently, we just hard-code the solution 3 above.
3496 next_gc_univ_laog = prev_next_gc_univ_laog + 1;
3497
3498 if (VG_(clo_stats))
3499 VG_(message)
3500 (Vg_DebugMsg,
philippebf37ae82015-05-03 10:56:16 +00003501 "univ_laog_do_GC cardinality entered %d exit %d next gc at %d\n",
3502 (Int)univ_laog_cardinality, (Int)seen, next_gc_univ_laog);
sewardj866c80c2011-10-22 19:29:51 +00003503}
3504
3505
sewardjb4112022007-11-09 22:49:28 +00003506__attribute__((noinline))
3507static void laog__add_edge ( Lock* src, Lock* dst ) {
florian6bf37262012-10-21 03:23:36 +00003508 UWord keyW;
sewardjb4112022007-11-09 22:49:28 +00003509 LAOGLinks* links;
3510 Bool presentF, presentR;
3511 if (0) VG_(printf)("laog__add_edge %p %p\n", src, dst);
3512
3513 /* Take the opportunity to sanity check the graph. Record in
3514 presentF if there is already a src->dst mapping in this node's
3515 forwards links, and presentR if there is already a src->dst
3516 mapping in this node's backwards links. They should agree!
3517 Also, we need to know whether the edge was already present so as
3518 to decide whether or not to update the link details mapping. We
3519 can compute presentF and presentR essentially for free, so may
3520 as well do this always. */
3521 presentF = presentR = False;
3522
3523 /* Update the out edges for src */
3524 keyW = 0;
3525 links = NULL;
florian6bf37262012-10-21 03:23:36 +00003526 if (VG_(lookupFM)( laog, &keyW, (UWord*)&links, (UWord)src )) {
sewardjb4112022007-11-09 22:49:28 +00003527 WordSetID outs_new;
3528 tl_assert(links);
florian6bf37262012-10-21 03:23:36 +00003529 tl_assert(keyW == (UWord)src);
3530 outs_new = HG_(addToWS)( univ_laog, links->outs, (UWord)dst );
sewardjb4112022007-11-09 22:49:28 +00003531 presentF = outs_new == links->outs;
3532 links->outs = outs_new;
3533 } else {
sewardjf98e1c02008-10-25 16:22:41 +00003534 links = HG_(zalloc)("hg.lae.1", sizeof(LAOGLinks));
sewardjb4112022007-11-09 22:49:28 +00003535 links->inns = HG_(emptyWS)( univ_laog );
florian6bf37262012-10-21 03:23:36 +00003536 links->outs = HG_(singletonWS)( univ_laog, (UWord)dst );
3537 VG_(addToFM)( laog, (UWord)src, (UWord)links );
sewardjb4112022007-11-09 22:49:28 +00003538 }
3539 /* Update the in edges for dst */
3540 keyW = 0;
3541 links = NULL;
florian6bf37262012-10-21 03:23:36 +00003542 if (VG_(lookupFM)( laog, &keyW, (UWord*)&links, (UWord)dst )) {
sewardjb4112022007-11-09 22:49:28 +00003543 WordSetID inns_new;
3544 tl_assert(links);
florian6bf37262012-10-21 03:23:36 +00003545 tl_assert(keyW == (UWord)dst);
3546 inns_new = HG_(addToWS)( univ_laog, links->inns, (UWord)src );
sewardjb4112022007-11-09 22:49:28 +00003547 presentR = inns_new == links->inns;
3548 links->inns = inns_new;
3549 } else {
sewardjf98e1c02008-10-25 16:22:41 +00003550 links = HG_(zalloc)("hg.lae.2", sizeof(LAOGLinks));
florian6bf37262012-10-21 03:23:36 +00003551 links->inns = HG_(singletonWS)( univ_laog, (UWord)src );
sewardjb4112022007-11-09 22:49:28 +00003552 links->outs = HG_(emptyWS)( univ_laog );
florian6bf37262012-10-21 03:23:36 +00003553 VG_(addToFM)( laog, (UWord)dst, (UWord)links );
sewardjb4112022007-11-09 22:49:28 +00003554 }
3555
3556 tl_assert( (presentF && presentR) || (!presentF && !presentR) );
3557
3558 if (!presentF && src->acquired_at && dst->acquired_at) {
3559 LAOGLinkExposition expo;
3560 /* If this edge is entering the graph, and we have acquired_at
3561 information for both src and dst, record those acquisition
3562 points. Hence, if there is later a violation of this
3563 ordering, we can show the user the two places in which the
3564 required src-dst ordering was previously established. */
barta0b6b2c2008-07-07 06:49:24 +00003565 if (0) VG_(printf)("acquire edge %#lx %#lx\n",
sewardjb4112022007-11-09 22:49:28 +00003566 src->guestaddr, dst->guestaddr);
3567 expo.src_ga = src->guestaddr;
3568 expo.dst_ga = dst->guestaddr;
3569 expo.src_ec = NULL;
3570 expo.dst_ec = NULL;
3571 tl_assert(laog_exposition);
florian6bf37262012-10-21 03:23:36 +00003572 if (VG_(lookupFM)( laog_exposition, NULL, NULL, (UWord)&expo )) {
sewardjb4112022007-11-09 22:49:28 +00003573 /* we already have it; do nothing */
3574 } else {
sewardjf98e1c02008-10-25 16:22:41 +00003575 LAOGLinkExposition* expo2 = HG_(zalloc)("hg.lae.3",
3576 sizeof(LAOGLinkExposition));
sewardjb4112022007-11-09 22:49:28 +00003577 expo2->src_ga = src->guestaddr;
3578 expo2->dst_ga = dst->guestaddr;
3579 expo2->src_ec = src->acquired_at;
3580 expo2->dst_ec = dst->acquired_at;
florian6bf37262012-10-21 03:23:36 +00003581 VG_(addToFM)( laog_exposition, (UWord)expo2, (UWord)NULL );
sewardjb4112022007-11-09 22:49:28 +00003582 }
3583 }
sewardj866c80c2011-10-22 19:29:51 +00003584
3585 if (HG_(cardinalityWSU) (univ_laog) >= next_gc_univ_laog)
3586 univ_laog_do_GC();
sewardjb4112022007-11-09 22:49:28 +00003587}
3588
3589__attribute__((noinline))
3590static void laog__del_edge ( Lock* src, Lock* dst ) {
florian6bf37262012-10-21 03:23:36 +00003591 UWord keyW;
sewardjb4112022007-11-09 22:49:28 +00003592 LAOGLinks* links;
sewardj866c80c2011-10-22 19:29:51 +00003593 if (0) VG_(printf)("laog__del_edge enter %p %p\n", src, dst);
sewardjb4112022007-11-09 22:49:28 +00003594 /* Update the out edges for src */
3595 keyW = 0;
3596 links = NULL;
florian6bf37262012-10-21 03:23:36 +00003597 if (VG_(lookupFM)( laog, &keyW, (UWord*)&links, (UWord)src )) {
sewardjb4112022007-11-09 22:49:28 +00003598 tl_assert(links);
florian6bf37262012-10-21 03:23:36 +00003599 tl_assert(keyW == (UWord)src);
3600 links->outs = HG_(delFromWS)( univ_laog, links->outs, (UWord)dst );
sewardjb4112022007-11-09 22:49:28 +00003601 }
3602 /* Update the in edges for dst */
3603 keyW = 0;
3604 links = NULL;
florian6bf37262012-10-21 03:23:36 +00003605 if (VG_(lookupFM)( laog, &keyW, (UWord*)&links, (UWord)dst )) {
sewardjb4112022007-11-09 22:49:28 +00003606 tl_assert(links);
florian6bf37262012-10-21 03:23:36 +00003607 tl_assert(keyW == (UWord)dst);
3608 links->inns = HG_(delFromWS)( univ_laog, links->inns, (UWord)src );
sewardjb4112022007-11-09 22:49:28 +00003609 }
sewardj866c80c2011-10-22 19:29:51 +00003610
3611 /* Remove the exposition of src,dst (if present) */
3612 {
3613 LAOGLinkExposition *fm_expo;
3614
3615 LAOGLinkExposition expo;
3616 expo.src_ga = src->guestaddr;
3617 expo.dst_ga = dst->guestaddr;
3618 expo.src_ec = NULL;
3619 expo.dst_ec = NULL;
3620
3621 if (VG_(delFromFM) (laog_exposition,
3622 (UWord*)&fm_expo, NULL, (UWord)&expo )) {
3623 HG_(free) (fm_expo);
3624 }
3625 }
3626
3627 /* deleting edges can increase nr of of WS so check for gc. */
3628 if (HG_(cardinalityWSU) (univ_laog) >= next_gc_univ_laog)
3629 univ_laog_do_GC();
3630 if (0) VG_(printf)("laog__del_edge exit\n");
sewardjb4112022007-11-09 22:49:28 +00003631}
3632
3633__attribute__((noinline))
3634static WordSetID /* in univ_laog */ laog__succs ( Lock* lk ) {
florian6bf37262012-10-21 03:23:36 +00003635 UWord keyW;
sewardjb4112022007-11-09 22:49:28 +00003636 LAOGLinks* links;
3637 keyW = 0;
3638 links = NULL;
florian6bf37262012-10-21 03:23:36 +00003639 if (VG_(lookupFM)( laog, &keyW, (UWord*)&links, (UWord)lk )) {
sewardjb4112022007-11-09 22:49:28 +00003640 tl_assert(links);
florian6bf37262012-10-21 03:23:36 +00003641 tl_assert(keyW == (UWord)lk);
sewardjb4112022007-11-09 22:49:28 +00003642 return links->outs;
3643 } else {
3644 return HG_(emptyWS)( univ_laog );
3645 }
3646}
3647
3648__attribute__((noinline))
3649static WordSetID /* in univ_laog */ laog__preds ( Lock* lk ) {
florian6bf37262012-10-21 03:23:36 +00003650 UWord keyW;
sewardjb4112022007-11-09 22:49:28 +00003651 LAOGLinks* links;
3652 keyW = 0;
3653 links = NULL;
florian6bf37262012-10-21 03:23:36 +00003654 if (VG_(lookupFM)( laog, &keyW, (UWord*)&links, (UWord)lk )) {
sewardjb4112022007-11-09 22:49:28 +00003655 tl_assert(links);
florian6bf37262012-10-21 03:23:36 +00003656 tl_assert(keyW == (UWord)lk);
sewardjb4112022007-11-09 22:49:28 +00003657 return links->inns;
3658 } else {
3659 return HG_(emptyWS)( univ_laog );
3660 }
3661}
3662
3663__attribute__((noinline))
florian6bf37262012-10-21 03:23:36 +00003664static void laog__sanity_check ( const HChar* who ) {
3665 UWord i, ws_size;
sewardj250ec2e2008-02-15 22:02:30 +00003666 UWord* ws_words;
sewardjb4112022007-11-09 22:49:28 +00003667 Lock* me;
3668 LAOGLinks* links;
sewardj896f6f92008-08-19 08:38:52 +00003669 VG_(initIterFM)( laog );
sewardjb4112022007-11-09 22:49:28 +00003670 me = NULL;
3671 links = NULL;
3672 if (0) VG_(printf)("laog sanity check\n");
florian6bf37262012-10-21 03:23:36 +00003673 while (VG_(nextIterFM)( laog, (UWord*)&me,
3674 (UWord*)&links )) {
sewardjb4112022007-11-09 22:49:28 +00003675 tl_assert(me);
3676 tl_assert(links);
3677 HG_(getPayloadWS)( &ws_words, &ws_size, univ_laog, links->inns );
3678 for (i = 0; i < ws_size; i++) {
3679 if ( ! HG_(elemWS)( univ_laog,
3680 laog__succs( (Lock*)ws_words[i] ),
florian6bf37262012-10-21 03:23:36 +00003681 (UWord)me ))
sewardjb4112022007-11-09 22:49:28 +00003682 goto bad;
3683 }
3684 HG_(getPayloadWS)( &ws_words, &ws_size, univ_laog, links->outs );
3685 for (i = 0; i < ws_size; i++) {
3686 if ( ! HG_(elemWS)( univ_laog,
3687 laog__preds( (Lock*)ws_words[i] ),
florian6bf37262012-10-21 03:23:36 +00003688 (UWord)me ))
sewardjb4112022007-11-09 22:49:28 +00003689 goto bad;
3690 }
3691 me = NULL;
3692 links = NULL;
3693 }
sewardj896f6f92008-08-19 08:38:52 +00003694 VG_(doneIterFM)( laog );
sewardjb4112022007-11-09 22:49:28 +00003695 return;
3696
3697 bad:
3698 VG_(printf)("laog__sanity_check(%s) FAILED\n", who);
3699 laog__show(who);
3700 tl_assert(0);
3701}
3702
3703/* If there is a path in laog from 'src' to any of the elements in
3704 'dst', return an arbitrarily chosen element of 'dst' reachable from
3705 'src'. If no path exist from 'src' to any element in 'dst', return
3706 NULL. */
3707__attribute__((noinline))
3708static
3709Lock* laog__do_dfs_from_to ( Lock* src, WordSetID dsts /* univ_lsets */ )
3710{
3711 Lock* ret;
florian6bf37262012-10-21 03:23:36 +00003712 Word ssz;
sewardjb4112022007-11-09 22:49:28 +00003713 XArray* stack; /* of Lock* */
3714 WordFM* visited; /* Lock* -> void, iow, Set(Lock*) */
3715 Lock* here;
3716 WordSetID succs;
florian6bf37262012-10-21 03:23:36 +00003717 UWord succs_size, i;
sewardj250ec2e2008-02-15 22:02:30 +00003718 UWord* succs_words;
sewardjb4112022007-11-09 22:49:28 +00003719 //laog__sanity_check();
3720
3721 /* If the destination set is empty, we can never get there from
3722 'src' :-), so don't bother to try */
3723 if (HG_(isEmptyWS)( univ_lsets, dsts ))
3724 return NULL;
3725
3726 ret = NULL;
sewardjf98e1c02008-10-25 16:22:41 +00003727 stack = VG_(newXA)( HG_(zalloc), "hg.lddft.1", HG_(free), sizeof(Lock*) );
3728 visited = VG_(newFM)( HG_(zalloc), "hg.lddft.2", HG_(free), NULL/*unboxedcmp*/ );
sewardjb4112022007-11-09 22:49:28 +00003729
3730 (void) VG_(addToXA)( stack, &src );
3731
3732 while (True) {
3733
3734 ssz = VG_(sizeXA)( stack );
3735
3736 if (ssz == 0) { ret = NULL; break; }
3737
3738 here = *(Lock**) VG_(indexXA)( stack, ssz-1 );
3739 VG_(dropTailXA)( stack, 1 );
3740
florian6bf37262012-10-21 03:23:36 +00003741 if (HG_(elemWS)( univ_lsets, dsts, (UWord)here )) { ret = here; break; }
sewardjb4112022007-11-09 22:49:28 +00003742
florian6bf37262012-10-21 03:23:36 +00003743 if (VG_(lookupFM)( visited, NULL, NULL, (UWord)here ))
sewardjb4112022007-11-09 22:49:28 +00003744 continue;
3745
florian6bf37262012-10-21 03:23:36 +00003746 VG_(addToFM)( visited, (UWord)here, 0 );
sewardjb4112022007-11-09 22:49:28 +00003747
3748 succs = laog__succs( here );
3749 HG_(getPayloadWS)( &succs_words, &succs_size, univ_laog, succs );
3750 for (i = 0; i < succs_size; i++)
3751 (void) VG_(addToXA)( stack, &succs_words[i] );
3752 }
3753
sewardj896f6f92008-08-19 08:38:52 +00003754 VG_(deleteFM)( visited, NULL, NULL );
sewardjb4112022007-11-09 22:49:28 +00003755 VG_(deleteXA)( stack );
3756 return ret;
3757}
3758
3759
3760/* Thread 'thr' is acquiring 'lk'. Check for inconsistent ordering
3761 between 'lk' and the locks already held by 'thr' and issue a
3762 complaint if so. Also, update the ordering graph appropriately.
3763*/
3764__attribute__((noinline))
3765static void laog__pre_thread_acquires_lock (
3766 Thread* thr, /* NB: BEFORE lock is added */
3767 Lock* lk
3768 )
3769{
sewardj250ec2e2008-02-15 22:02:30 +00003770 UWord* ls_words;
florian6bf37262012-10-21 03:23:36 +00003771 UWord ls_size, i;
sewardjb4112022007-11-09 22:49:28 +00003772 Lock* other;
3773
3774 /* It may be that 'thr' already holds 'lk' and is recursively
3775 relocking in. In this case we just ignore the call. */
3776 /* NB: univ_lsets really is correct here */
florian6bf37262012-10-21 03:23:36 +00003777 if (HG_(elemWS)( univ_lsets, thr->locksetA, (UWord)lk ))
sewardjb4112022007-11-09 22:49:28 +00003778 return;
3779
sewardjb4112022007-11-09 22:49:28 +00003780 /* First, the check. Complain if there is any path in laog from lk
3781 to any of the locks already held by thr, since if any such path
3782 existed, it would mean that previously lk was acquired before
3783 (rather than after, as we are doing here) at least one of those
3784 locks.
3785 */
3786 other = laog__do_dfs_from_to(lk, thr->locksetA);
3787 if (other) {
3788 LAOGLinkExposition key, *found;
3789 /* So we managed to find a path lk --*--> other in the graph,
3790 which implies that 'lk' should have been acquired before
3791 'other' but is in fact being acquired afterwards. We present
3792 the lk/other arguments to record_error_LockOrder in the order
3793 in which they should have been acquired. */
3794 /* Go look in the laog_exposition mapping, to find the allocation
3795 points for this edge, so we can show the user. */
3796 key.src_ga = lk->guestaddr;
3797 key.dst_ga = other->guestaddr;
3798 key.src_ec = NULL;
3799 key.dst_ec = NULL;
3800 found = NULL;
sewardj896f6f92008-08-19 08:38:52 +00003801 if (VG_(lookupFM)( laog_exposition,
florian6bf37262012-10-21 03:23:36 +00003802 (UWord*)&found, NULL, (UWord)&key )) {
sewardjb4112022007-11-09 22:49:28 +00003803 tl_assert(found != &key);
3804 tl_assert(found->src_ga == key.src_ga);
3805 tl_assert(found->dst_ga == key.dst_ga);
3806 tl_assert(found->src_ec);
3807 tl_assert(found->dst_ec);
sewardjf98e1c02008-10-25 16:22:41 +00003808 HG_(record_error_LockOrder)(
philippe46daf0d2014-07-29 20:08:15 +00003809 thr, lk, other,
sewardjffce8152011-06-24 10:09:41 +00003810 found->src_ec, found->dst_ec, other->acquired_at );
sewardjb4112022007-11-09 22:49:28 +00003811 } else {
3812 /* Hmm. This can't happen (can it?) */
philippeebe25802013-01-30 23:21:34 +00003813 /* Yes, it can happen: see tests/tc14_laog_dinphils.
3814 Imagine we have 3 philosophers A B C, and the forks
3815 between them:
3816
3817 C
3818
3819 fCA fBC
3820
3821 A fAB B
3822
3823 Let's have the following actions:
3824 A takes fCA,fAB
3825 A releases fCA,fAB
3826 B takes fAB,fBC
3827 B releases fAB,fBC
3828 C takes fBC,fCA
3829 C releases fBC,fCA
3830
3831 Helgrind will report a lock order error when C takes fCA.
3832 Effectively, we have a deadlock if the following
3833 sequence is done:
3834 A takes fCA
3835 B takes fAB
3836 C takes fBC
3837
3838 The error reported is:
3839 Observed (incorrect) order fBC followed by fCA
3840 but the stack traces that have established the required order
3841 are not given.
3842
3843 This is because there is no pair (fCA, fBC) in laog exposition :
3844 the laog_exposition records all pairs of locks between a new lock
3845 taken by a thread and all the already taken locks.
3846 So, there is no laog_exposition (fCA, fBC) as no thread ever
3847 first locked fCA followed by fBC.
3848
3849 In other words, when the deadlock cycle involves more than
3850 two locks, then helgrind does not report the sequence of
3851 operations that created the cycle.
3852
3853 However, we can report the current stack trace (where
3854 lk is being taken), and the stack trace where other was acquired:
3855 Effectively, the variable 'other' contains a lock currently
3856 held by this thread, with its 'acquired_at'. */
3857
sewardjf98e1c02008-10-25 16:22:41 +00003858 HG_(record_error_LockOrder)(
philippe46daf0d2014-07-29 20:08:15 +00003859 thr, lk, other,
philippeebe25802013-01-30 23:21:34 +00003860 NULL, NULL, other->acquired_at );
sewardjb4112022007-11-09 22:49:28 +00003861 }
3862 }
3863
3864 /* Second, add to laog the pairs
3865 (old, lk) | old <- locks already held by thr
3866 Since both old and lk are currently held by thr, their acquired_at
3867 fields must be non-NULL.
3868 */
3869 tl_assert(lk->acquired_at);
3870 HG_(getPayloadWS)( &ls_words, &ls_size, univ_lsets, thr->locksetA );
3871 for (i = 0; i < ls_size; i++) {
3872 Lock* old = (Lock*)ls_words[i];
3873 tl_assert(old->acquired_at);
3874 laog__add_edge( old, lk );
3875 }
3876
3877 /* Why "except_Locks" ? We're here because a lock is being
3878 acquired by a thread, and we're in an inconsistent state here.
3879 See the call points in evhH__post_thread_{r,w}_acquires_lock.
3880 When called in this inconsistent state, locks__sanity_check duly
3881 barfs. */
sewardjf98e1c02008-10-25 16:22:41 +00003882 if (HG_(clo_sanity_flags) & SCE_LAOG)
sewardjb4112022007-11-09 22:49:28 +00003883 all_except_Locks__sanity_check("laog__pre_thread_acquires_lock-post");
3884}
3885
sewardj866c80c2011-10-22 19:29:51 +00003886/* Allocates a duplicate of words. Caller must HG_(free) the result. */
3887static UWord* UWordV_dup(UWord* words, Word words_size)
3888{
3889 UInt i;
3890
3891 if (words_size == 0)
3892 return NULL;
3893
3894 UWord *dup = HG_(zalloc) ("hg.dup.1", (SizeT) words_size * sizeof(UWord));
3895
3896 for (i = 0; i < words_size; i++)
3897 dup[i] = words[i];
3898
3899 return dup;
3900}
sewardjb4112022007-11-09 22:49:28 +00003901
3902/* Delete from 'laog' any pair mentioning a lock in locksToDelete */
3903
3904__attribute__((noinline))
3905static void laog__handle_one_lock_deletion ( Lock* lk )
3906{
3907 WordSetID preds, succs;
florian6bf37262012-10-21 03:23:36 +00003908 UWord preds_size, succs_size, i, j;
sewardj250ec2e2008-02-15 22:02:30 +00003909 UWord *preds_words, *succs_words;
sewardjb4112022007-11-09 22:49:28 +00003910
3911 preds = laog__preds( lk );
3912 succs = laog__succs( lk );
3913
sewardj866c80c2011-10-22 19:29:51 +00003914 // We need to duplicate the payload, as these can be garbage collected
3915 // during the del/add operations below.
sewardjb4112022007-11-09 22:49:28 +00003916 HG_(getPayloadWS)( &preds_words, &preds_size, univ_laog, preds );
sewardj866c80c2011-10-22 19:29:51 +00003917 preds_words = UWordV_dup(preds_words, preds_size);
3918
3919 HG_(getPayloadWS)( &succs_words, &succs_size, univ_laog, succs );
3920 succs_words = UWordV_dup(succs_words, succs_size);
3921
sewardjb4112022007-11-09 22:49:28 +00003922 for (i = 0; i < preds_size; i++)
3923 laog__del_edge( (Lock*)preds_words[i], lk );
3924
sewardjb4112022007-11-09 22:49:28 +00003925 for (j = 0; j < succs_size; j++)
3926 laog__del_edge( lk, (Lock*)succs_words[j] );
3927
3928 for (i = 0; i < preds_size; i++) {
3929 for (j = 0; j < succs_size; j++) {
3930 if (preds_words[i] != succs_words[j]) {
3931 /* This can pass unlocked locks to laog__add_edge, since
3932 we're deleting stuff. So their acquired_at fields may
3933 be NULL. */
3934 laog__add_edge( (Lock*)preds_words[i], (Lock*)succs_words[j] );
3935 }
3936 }
3937 }
sewardj866c80c2011-10-22 19:29:51 +00003938
3939 if (preds_words)
3940 HG_(free) (preds_words);
3941 if (succs_words)
3942 HG_(free) (succs_words);
3943
3944 // Remove lk information from laog links FM
3945 {
3946 LAOGLinks *links;
3947 Lock* linked_lk;
3948
3949 if (VG_(delFromFM) (laog,
3950 (UWord*)&linked_lk, (UWord*)&links, (UWord)lk)) {
3951 tl_assert (linked_lk == lk);
3952 HG_(free) (links);
3953 }
3954 }
3955 /* FIXME ??? What about removing lock lk data from EXPOSITION ??? */
sewardjb4112022007-11-09 22:49:28 +00003956}
3957
sewardj1cbc12f2008-11-10 16:16:46 +00003958//__attribute__((noinline))
3959//static void laog__handle_lock_deletions (
3960// WordSetID /* in univ_laog */ locksToDelete
3961// )
3962//{
3963// Word i, ws_size;
3964// UWord* ws_words;
3965//
sewardj1cbc12f2008-11-10 16:16:46 +00003966//
3967// HG_(getPayloadWS)( &ws_words, &ws_size, univ_lsets, locksToDelete );
sewardj866c80c2011-10-22 19:29:51 +00003968// UWordV_dup call needed here ...
sewardj1cbc12f2008-11-10 16:16:46 +00003969// for (i = 0; i < ws_size; i++)
3970// laog__handle_one_lock_deletion( (Lock*)ws_words[i] );
3971//
3972// if (HG_(clo_sanity_flags) & SCE_LAOG)
3973// all__sanity_check("laog__handle_lock_deletions-post");
3974//}
sewardjb4112022007-11-09 22:49:28 +00003975
3976
3977/*--------------------------------------------------------------*/
3978/*--- Malloc/free replacements ---*/
3979/*--------------------------------------------------------------*/
3980
3981typedef
3982 struct {
3983 void* next; /* required by m_hashtable */
3984 Addr payload; /* ptr to actual block */
3985 SizeT szB; /* size requested */
3986 ExeContext* where; /* where it was allocated */
3987 Thread* thr; /* allocating thread */
3988 }
3989 MallocMeta;
3990
3991/* A hash table of MallocMetas, used to track malloc'd blocks
3992 (obviously). */
florian09a4c792014-10-18 10:58:05 +00003993static VgHashTable *hg_mallocmeta_table = NULL;
sewardjb4112022007-11-09 22:49:28 +00003994
philippe5fbc9762013-12-01 19:28:48 +00003995/* MallocMeta are small elements. We use a pool to avoid
3996 the overhead of malloc for each MallocMeta. */
3997static PoolAlloc *MallocMeta_poolalloc = NULL;
sewardjb4112022007-11-09 22:49:28 +00003998
3999static MallocMeta* new_MallocMeta ( void ) {
philippe5fbc9762013-12-01 19:28:48 +00004000 MallocMeta* md = VG_(allocEltPA) (MallocMeta_poolalloc);
4001 VG_(memset)(md, 0, sizeof(MallocMeta));
sewardjb4112022007-11-09 22:49:28 +00004002 return md;
4003}
4004static void delete_MallocMeta ( MallocMeta* md ) {
philippe5fbc9762013-12-01 19:28:48 +00004005 VG_(freeEltPA)(MallocMeta_poolalloc, md);
sewardjb4112022007-11-09 22:49:28 +00004006}
4007
4008
4009/* Allocate a client block and set up the metadata for it. */
4010
4011static
4012void* handle_alloc ( ThreadId tid,
4013 SizeT szB, SizeT alignB, Bool is_zeroed )
4014{
4015 Addr p;
4016 MallocMeta* md;
4017
4018 tl_assert( ((SSizeT)szB) >= 0 );
4019 p = (Addr)VG_(cli_malloc)(alignB, szB);
4020 if (!p) {
4021 return NULL;
4022 }
4023 if (is_zeroed)
4024 VG_(memset)((void*)p, 0, szB);
4025
4026 /* Note that map_threads_lookup must succeed (cannot assert), since
4027 memory can only be allocated by currently alive threads, hence
4028 they must have an entry in map_threads. */
4029 md = new_MallocMeta();
4030 md->payload = p;
4031 md->szB = szB;
4032 md->where = VG_(record_ExeContext)( tid, 0 );
4033 md->thr = map_threads_lookup( tid );
4034
4035 VG_(HT_add_node)( hg_mallocmeta_table, (VgHashNode*)md );
4036
4037 /* Tell the lower level memory wranglers. */
4038 evh__new_mem_heap( p, szB, is_zeroed );
4039
4040 return (void*)p;
4041}
4042
4043/* Re the checks for less-than-zero (also in hg_cli__realloc below):
4044 Cast to a signed type to catch any unexpectedly negative args.
4045 We're assuming here that the size asked for is not greater than
4046 2^31 bytes (for 32-bit platforms) or 2^63 bytes (for 64-bit
4047 platforms). */
4048static void* hg_cli__malloc ( ThreadId tid, SizeT n ) {
4049 if (((SSizeT)n) < 0) return NULL;
4050 return handle_alloc ( tid, n, VG_(clo_alignment),
4051 /*is_zeroed*/False );
4052}
4053static void* hg_cli____builtin_new ( ThreadId tid, SizeT n ) {
4054 if (((SSizeT)n) < 0) return NULL;
4055 return handle_alloc ( tid, n, VG_(clo_alignment),
4056 /*is_zeroed*/False );
4057}
4058static void* hg_cli____builtin_vec_new ( ThreadId tid, SizeT n ) {
4059 if (((SSizeT)n) < 0) return NULL;
4060 return handle_alloc ( tid, n, VG_(clo_alignment),
4061 /*is_zeroed*/False );
4062}
4063static void* hg_cli__memalign ( ThreadId tid, SizeT align, SizeT n ) {
4064 if (((SSizeT)n) < 0) return NULL;
4065 return handle_alloc ( tid, n, align,
4066 /*is_zeroed*/False );
4067}
4068static void* hg_cli__calloc ( ThreadId tid, SizeT nmemb, SizeT size1 ) {
4069 if ( ((SSizeT)nmemb) < 0 || ((SSizeT)size1) < 0 ) return NULL;
4070 return handle_alloc ( tid, nmemb*size1, VG_(clo_alignment),
4071 /*is_zeroed*/True );
4072}
4073
4074
4075/* Free a client block, including getting rid of the relevant
4076 metadata. */
4077
4078static void handle_free ( ThreadId tid, void* p )
4079{
4080 MallocMeta *md, *old_md;
4081 SizeT szB;
4082
4083 /* First see if we can find the metadata for 'p'. */
4084 md = (MallocMeta*) VG_(HT_lookup)( hg_mallocmeta_table, (UWord)p );
4085 if (!md)
4086 return; /* apparently freeing a bogus address. Oh well. */
4087
4088 tl_assert(md->payload == (Addr)p);
4089 szB = md->szB;
4090
4091 /* Nuke the metadata block */
4092 old_md = (MallocMeta*)
4093 VG_(HT_remove)( hg_mallocmeta_table, (UWord)p );
4094 tl_assert(old_md); /* it must be present - we just found it */
4095 tl_assert(old_md == md);
4096 tl_assert(old_md->payload == (Addr)p);
4097
4098 VG_(cli_free)((void*)old_md->payload);
4099 delete_MallocMeta(old_md);
4100
4101 /* Tell the lower level memory wranglers. */
4102 evh__die_mem_heap( (Addr)p, szB );
4103}
4104
4105static void hg_cli__free ( ThreadId tid, void* p ) {
4106 handle_free(tid, p);
4107}
4108static void hg_cli____builtin_delete ( ThreadId tid, void* p ) {
4109 handle_free(tid, p);
4110}
4111static void hg_cli____builtin_vec_delete ( ThreadId tid, void* p ) {
4112 handle_free(tid, p);
4113}
4114
4115
4116static void* hg_cli__realloc ( ThreadId tid, void* payloadV, SizeT new_size )
4117{
4118 MallocMeta *md, *md_new, *md_tmp;
4119 SizeT i;
4120
4121 Addr payload = (Addr)payloadV;
4122
4123 if (((SSizeT)new_size) < 0) return NULL;
4124
4125 md = (MallocMeta*) VG_(HT_lookup)( hg_mallocmeta_table, (UWord)payload );
4126 if (!md)
4127 return NULL; /* apparently realloc-ing a bogus address. Oh well. */
4128
4129 tl_assert(md->payload == payload);
4130
4131 if (md->szB == new_size) {
4132 /* size unchanged */
4133 md->where = VG_(record_ExeContext)(tid, 0);
4134 return payloadV;
4135 }
4136
4137 if (md->szB > new_size) {
4138 /* new size is smaller */
4139 md->szB = new_size;
4140 md->where = VG_(record_ExeContext)(tid, 0);
4141 evh__die_mem_heap( md->payload + new_size, md->szB - new_size );
4142 return payloadV;
4143 }
4144
4145 /* else */ {
4146 /* new size is bigger */
4147 Addr p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
4148
4149 /* First half kept and copied, second half new */
4150 // FIXME: shouldn't we use a copier which implements the
4151 // memory state machine?
sewardj23f12002009-07-24 08:45:08 +00004152 evh__copy_mem( payload, p_new, md->szB );
sewardjb4112022007-11-09 22:49:28 +00004153 evh__new_mem_heap ( p_new + md->szB, new_size - md->szB,
sewardjf98e1c02008-10-25 16:22:41 +00004154 /*inited*/False );
sewardjb4112022007-11-09 22:49:28 +00004155 /* FIXME: can anything funny happen here? specifically, if the
4156 old range contained a lock, then die_mem_heap will complain.
4157 Is that the correct behaviour? Not sure. */
4158 evh__die_mem_heap( payload, md->szB );
4159
4160 /* Copy from old to new */
4161 for (i = 0; i < md->szB; i++)
4162 ((UChar*)p_new)[i] = ((UChar*)payload)[i];
4163
4164 /* Because the metadata hash table is index by payload address,
4165 we have to get rid of the old hash table entry and make a new
4166 one. We can't just modify the existing metadata in place,
4167 because then it would (almost certainly) be in the wrong hash
4168 chain. */
4169 md_new = new_MallocMeta();
4170 *md_new = *md;
4171
4172 md_tmp = VG_(HT_remove)( hg_mallocmeta_table, payload );
4173 tl_assert(md_tmp);
4174 tl_assert(md_tmp == md);
4175
4176 VG_(cli_free)((void*)md->payload);
4177 delete_MallocMeta(md);
4178
4179 /* Update fields */
4180 md_new->where = VG_(record_ExeContext)( tid, 0 );
4181 md_new->szB = new_size;
4182 md_new->payload = p_new;
4183 md_new->thr = map_threads_lookup( tid );
4184
4185 /* and add */
4186 VG_(HT_add_node)( hg_mallocmeta_table, (VgHashNode*)md_new );
4187
4188 return (void*)p_new;
4189 }
4190}
4191
njn8b140de2009-02-17 04:31:18 +00004192static SizeT hg_cli_malloc_usable_size ( ThreadId tid, void* p )
4193{
4194 MallocMeta *md = VG_(HT_lookup)( hg_mallocmeta_table, (UWord)p );
4195
4196 // There may be slop, but pretend there isn't because only the asked-for
4197 // area will have been shadowed properly.
4198 return ( md ? md->szB : 0 );
4199}
4200
sewardjb4112022007-11-09 22:49:28 +00004201
sewardj095d61e2010-03-11 13:43:18 +00004202/* For error creation: map 'data_addr' to a malloc'd chunk, if any.
sewardjc8028ad2010-05-05 09:34:42 +00004203 Slow linear search. With a bit of hash table help if 'data_addr'
4204 is either the start of a block or up to 15 word-sized steps along
4205 from the start of a block. */
sewardj095d61e2010-03-11 13:43:18 +00004206
4207static inline Bool addr_is_in_MM_Chunk( MallocMeta* mm, Addr a )
4208{
sewardjc8028ad2010-05-05 09:34:42 +00004209 /* Accept 'a' as within 'mm' if 'mm's size is zero and 'a' points
4210 right at it. */
4211 if (UNLIKELY(mm->szB == 0 && a == mm->payload))
4212 return True;
4213 /* else normal interval rules apply */
4214 if (LIKELY(a < mm->payload)) return False;
4215 if (LIKELY(a >= mm->payload + mm->szB)) return False;
4216 return True;
sewardj095d61e2010-03-11 13:43:18 +00004217}
4218
sewardjc8028ad2010-05-05 09:34:42 +00004219Bool HG_(mm_find_containing_block)( /*OUT*/ExeContext** where,
philippe0c9ac8d2014-07-18 00:03:58 +00004220 /*OUT*/UInt* tnr,
sewardj095d61e2010-03-11 13:43:18 +00004221 /*OUT*/Addr* payload,
4222 /*OUT*/SizeT* szB,
4223 Addr data_addr )
4224{
4225 MallocMeta* mm;
sewardjc8028ad2010-05-05 09:34:42 +00004226 Int i;
4227 const Int n_fast_check_words = 16;
4228
4229 /* First, do a few fast searches on the basis that data_addr might
4230 be exactly the start of a block or up to 15 words inside. This
4231 can happen commonly via the creq
4232 _VG_USERREQ__HG_CLEAN_MEMORY_HEAPBLOCK. */
4233 for (i = 0; i < n_fast_check_words; i++) {
4234 mm = VG_(HT_lookup)( hg_mallocmeta_table,
4235 data_addr - (UWord)(UInt)i * sizeof(UWord) );
4236 if (UNLIKELY(mm && addr_is_in_MM_Chunk(mm, data_addr)))
4237 goto found;
4238 }
4239
sewardj095d61e2010-03-11 13:43:18 +00004240 /* Well, this totally sucks. But without using an interval tree or
sewardjc8028ad2010-05-05 09:34:42 +00004241 some such, it's hard to see how to do better. We have to check
4242 every block in the entire table. */
sewardj095d61e2010-03-11 13:43:18 +00004243 VG_(HT_ResetIter)(hg_mallocmeta_table);
4244 while ( (mm = VG_(HT_Next)(hg_mallocmeta_table)) ) {
sewardjc8028ad2010-05-05 09:34:42 +00004245 if (UNLIKELY(addr_is_in_MM_Chunk(mm, data_addr)))
4246 goto found;
sewardj095d61e2010-03-11 13:43:18 +00004247 }
sewardjc8028ad2010-05-05 09:34:42 +00004248
4249 /* Not found. Bah. */
4250 return False;
4251 /*NOTREACHED*/
4252
4253 found:
4254 tl_assert(mm);
4255 tl_assert(addr_is_in_MM_Chunk(mm, data_addr));
4256 if (where) *where = mm->where;
philippe0c9ac8d2014-07-18 00:03:58 +00004257 if (tnr) *tnr = mm->thr->errmsg_index;
sewardjc8028ad2010-05-05 09:34:42 +00004258 if (payload) *payload = mm->payload;
4259 if (szB) *szB = mm->szB;
4260 return True;
sewardj095d61e2010-03-11 13:43:18 +00004261}
4262
4263
sewardjb4112022007-11-09 22:49:28 +00004264/*--------------------------------------------------------------*/
4265/*--- Instrumentation ---*/
4266/*--------------------------------------------------------------*/
4267
sewardjcafe5052013-01-17 14:24:35 +00004268#define unop(_op, _arg1) IRExpr_Unop((_op),(_arg1))
sewardjffce8152011-06-24 10:09:41 +00004269#define binop(_op, _arg1, _arg2) IRExpr_Binop((_op),(_arg1),(_arg2))
4270#define mkexpr(_tmp) IRExpr_RdTmp((_tmp))
4271#define mkU32(_n) IRExpr_Const(IRConst_U32(_n))
4272#define mkU64(_n) IRExpr_Const(IRConst_U64(_n))
4273#define assign(_t, _e) IRStmt_WrTmp((_t), (_e))
4274
sewardjcafe5052013-01-17 14:24:35 +00004275/* This takes and returns atoms, of course. Not full IRExprs. */
4276static IRExpr* mk_And1 ( IRSB* sbOut, IRExpr* arg1, IRExpr* arg2 )
4277{
4278 tl_assert(arg1 && arg2);
4279 tl_assert(isIRAtom(arg1));
4280 tl_assert(isIRAtom(arg2));
4281 /* Generate 32to1(And32(1Uto32(arg1), 1Uto32(arg2))). Appalling
4282 code, I know. */
4283 IRTemp wide1 = newIRTemp(sbOut->tyenv, Ity_I32);
4284 IRTemp wide2 = newIRTemp(sbOut->tyenv, Ity_I32);
4285 IRTemp anded = newIRTemp(sbOut->tyenv, Ity_I32);
4286 IRTemp res = newIRTemp(sbOut->tyenv, Ity_I1);
4287 addStmtToIRSB(sbOut, assign(wide1, unop(Iop_1Uto32, arg1)));
4288 addStmtToIRSB(sbOut, assign(wide2, unop(Iop_1Uto32, arg2)));
4289 addStmtToIRSB(sbOut, assign(anded, binop(Iop_And32, mkexpr(wide1),
4290 mkexpr(wide2))));
4291 addStmtToIRSB(sbOut, assign(res, unop(Iop_32to1, mkexpr(anded))));
4292 return mkexpr(res);
4293}
4294
sewardjffce8152011-06-24 10:09:41 +00004295static void instrument_mem_access ( IRSB* sbOut,
sewardjb4112022007-11-09 22:49:28 +00004296 IRExpr* addr,
4297 Int szB,
4298 Bool isStore,
sewardjffce8152011-06-24 10:09:41 +00004299 Int hWordTy_szB,
sewardjcafe5052013-01-17 14:24:35 +00004300 Int goff_sp,
4301 IRExpr* guard ) /* NULL => True */
sewardjb4112022007-11-09 22:49:28 +00004302{
4303 IRType tyAddr = Ity_INVALID;
florian6bf37262012-10-21 03:23:36 +00004304 const HChar* hName = NULL;
sewardjb4112022007-11-09 22:49:28 +00004305 void* hAddr = NULL;
4306 Int regparms = 0;
4307 IRExpr** argv = NULL;
4308 IRDirty* di = NULL;
4309
sewardjffce8152011-06-24 10:09:41 +00004310 // THRESH is the size of the window above SP (well,
4311 // mostly above) that we assume implies a stack reference.
4312 const Int THRESH = 4096 * 4; // somewhat arbitrary
4313 const Int rz_szB = VG_STACK_REDZONE_SZB;
4314
sewardjb4112022007-11-09 22:49:28 +00004315 tl_assert(isIRAtom(addr));
4316 tl_assert(hWordTy_szB == 4 || hWordTy_szB == 8);
4317
sewardjffce8152011-06-24 10:09:41 +00004318 tyAddr = typeOfIRExpr( sbOut->tyenv, addr );
sewardjb4112022007-11-09 22:49:28 +00004319 tl_assert(tyAddr == Ity_I32 || tyAddr == Ity_I64);
4320
4321 /* So the effective address is in 'addr' now. */
4322 regparms = 1; // unless stated otherwise
4323 if (isStore) {
4324 switch (szB) {
4325 case 1:
sewardj23f12002009-07-24 08:45:08 +00004326 hName = "evh__mem_help_cwrite_1";
4327 hAddr = &evh__mem_help_cwrite_1;
sewardjb4112022007-11-09 22:49:28 +00004328 argv = mkIRExprVec_1( addr );
4329 break;
4330 case 2:
sewardj23f12002009-07-24 08:45:08 +00004331 hName = "evh__mem_help_cwrite_2";
4332 hAddr = &evh__mem_help_cwrite_2;
sewardjb4112022007-11-09 22:49:28 +00004333 argv = mkIRExprVec_1( addr );
4334 break;
4335 case 4:
sewardj23f12002009-07-24 08:45:08 +00004336 hName = "evh__mem_help_cwrite_4";
4337 hAddr = &evh__mem_help_cwrite_4;
sewardjb4112022007-11-09 22:49:28 +00004338 argv = mkIRExprVec_1( addr );
4339 break;
4340 case 8:
sewardj23f12002009-07-24 08:45:08 +00004341 hName = "evh__mem_help_cwrite_8";
4342 hAddr = &evh__mem_help_cwrite_8;
sewardjb4112022007-11-09 22:49:28 +00004343 argv = mkIRExprVec_1( addr );
4344 break;
4345 default:
4346 tl_assert(szB > 8 && szB <= 512); /* stay sane */
4347 regparms = 2;
sewardj23f12002009-07-24 08:45:08 +00004348 hName = "evh__mem_help_cwrite_N";
4349 hAddr = &evh__mem_help_cwrite_N;
sewardjb4112022007-11-09 22:49:28 +00004350 argv = mkIRExprVec_2( addr, mkIRExpr_HWord( szB ));
4351 break;
4352 }
4353 } else {
4354 switch (szB) {
4355 case 1:
sewardj23f12002009-07-24 08:45:08 +00004356 hName = "evh__mem_help_cread_1";
4357 hAddr = &evh__mem_help_cread_1;
sewardjb4112022007-11-09 22:49:28 +00004358 argv = mkIRExprVec_1( addr );
4359 break;
4360 case 2:
sewardj23f12002009-07-24 08:45:08 +00004361 hName = "evh__mem_help_cread_2";
4362 hAddr = &evh__mem_help_cread_2;
sewardjb4112022007-11-09 22:49:28 +00004363 argv = mkIRExprVec_1( addr );
4364 break;
4365 case 4:
sewardj23f12002009-07-24 08:45:08 +00004366 hName = "evh__mem_help_cread_4";
4367 hAddr = &evh__mem_help_cread_4;
sewardjb4112022007-11-09 22:49:28 +00004368 argv = mkIRExprVec_1( addr );
4369 break;
4370 case 8:
sewardj23f12002009-07-24 08:45:08 +00004371 hName = "evh__mem_help_cread_8";
4372 hAddr = &evh__mem_help_cread_8;
sewardjb4112022007-11-09 22:49:28 +00004373 argv = mkIRExprVec_1( addr );
4374 break;
4375 default:
4376 tl_assert(szB > 8 && szB <= 512); /* stay sane */
4377 regparms = 2;
sewardj23f12002009-07-24 08:45:08 +00004378 hName = "evh__mem_help_cread_N";
4379 hAddr = &evh__mem_help_cread_N;
sewardjb4112022007-11-09 22:49:28 +00004380 argv = mkIRExprVec_2( addr, mkIRExpr_HWord( szB ));
4381 break;
4382 }
4383 }
4384
sewardjffce8152011-06-24 10:09:41 +00004385 /* Create the helper. */
sewardjb4112022007-11-09 22:49:28 +00004386 tl_assert(hName);
4387 tl_assert(hAddr);
4388 tl_assert(argv);
4389 di = unsafeIRDirty_0_N( regparms,
4390 hName, VG_(fnptr_to_fnentry)( hAddr ),
4391 argv );
sewardjffce8152011-06-24 10:09:41 +00004392
4393 if (! HG_(clo_check_stack_refs)) {
4394 /* We're ignoring memory references which are (obviously) to the
4395 stack. In fact just skip stack refs that are within 4 pages
4396 of SP (SP - the redzone, really), as that's simple, easy, and
4397 filters out most stack references. */
4398 /* Generate the guard condition: "(addr - (SP - RZ)) >u N", for
4399 some arbitrary N. If that is true then addr is outside the
4400 range (SP - RZ .. SP + N - RZ). If N is smallish (a few
4401 pages) then we can say addr is within a few pages of SP and
4402 so can't possibly be a heap access, and so can be skipped.
4403
4404 Note that the condition simplifies to
4405 (addr - SP + RZ) >u N
4406 which generates better code in x86/amd64 backends, but it does
4407 not unfortunately simplify to
4408 (addr - SP) >u (N - RZ)
4409 (would be beneficial because N - RZ is a constant) because
4410 wraparound arithmetic messes up the comparison. eg.
4411 20 >u 10 == True,
4412 but (20 - 15) >u (10 - 15) == 5 >u (MAXINT-5) == False.
4413 */
4414 IRTemp sp = newIRTemp(sbOut->tyenv, tyAddr);
4415 addStmtToIRSB( sbOut, assign(sp, IRExpr_Get(goff_sp, tyAddr)));
4416
4417 /* "addr - SP" */
4418 IRTemp addr_minus_sp = newIRTemp(sbOut->tyenv, tyAddr);
4419 addStmtToIRSB(
4420 sbOut,
4421 assign(addr_minus_sp,
4422 tyAddr == Ity_I32
4423 ? binop(Iop_Sub32, addr, mkexpr(sp))
4424 : binop(Iop_Sub64, addr, mkexpr(sp)))
4425 );
4426
4427 /* "addr - SP + RZ" */
4428 IRTemp diff = newIRTemp(sbOut->tyenv, tyAddr);
4429 addStmtToIRSB(
4430 sbOut,
4431 assign(diff,
4432 tyAddr == Ity_I32
4433 ? binop(Iop_Add32, mkexpr(addr_minus_sp), mkU32(rz_szB))
4434 : binop(Iop_Add64, mkexpr(addr_minus_sp), mkU64(rz_szB)))
4435 );
4436
sewardjcafe5052013-01-17 14:24:35 +00004437 /* guardA == "guard on the address" */
4438 IRTemp guardA = newIRTemp(sbOut->tyenv, Ity_I1);
sewardjffce8152011-06-24 10:09:41 +00004439 addStmtToIRSB(
4440 sbOut,
sewardjcafe5052013-01-17 14:24:35 +00004441 assign(guardA,
sewardjffce8152011-06-24 10:09:41 +00004442 tyAddr == Ity_I32
4443 ? binop(Iop_CmpLT32U, mkU32(THRESH), mkexpr(diff))
4444 : binop(Iop_CmpLT64U, mkU64(THRESH), mkexpr(diff)))
4445 );
sewardjcafe5052013-01-17 14:24:35 +00004446 di->guard = mkexpr(guardA);
4447 }
4448
4449 /* If there's a guard on the access itself (as supplied by the
4450 caller of this routine), we need to AND that in to any guard we
4451 might already have. */
4452 if (guard) {
4453 di->guard = mk_And1(sbOut, di->guard, guard);
sewardjffce8152011-06-24 10:09:41 +00004454 }
4455
4456 /* Add the helper. */
4457 addStmtToIRSB( sbOut, IRStmt_Dirty(di) );
sewardjb4112022007-11-09 22:49:28 +00004458}
4459
4460
sewardja0eee322009-07-31 08:46:35 +00004461/* Figure out if GA is a guest code address in the dynamic linker, and
4462 if so return True. Otherwise (and in case of any doubt) return
4463 False. (sidedly safe w/ False as the safe value) */
florianf466eef2015-01-02 17:32:40 +00004464static Bool is_in_dynamic_linker_shared_object( Addr ga )
sewardja0eee322009-07-31 08:46:35 +00004465{
4466 DebugInfo* dinfo;
florian19f91bb2012-11-10 22:29:54 +00004467 const HChar* soname;
sewardja0eee322009-07-31 08:46:35 +00004468 if (0) return False;
4469
florianf466eef2015-01-02 17:32:40 +00004470 dinfo = VG_(find_DebugInfo)( ga );
sewardja0eee322009-07-31 08:46:35 +00004471 if (!dinfo) return False;
4472
sewardje3f1e592009-07-31 09:41:29 +00004473 soname = VG_(DebugInfo_get_soname)(dinfo);
sewardja0eee322009-07-31 08:46:35 +00004474 tl_assert(soname);
4475 if (0) VG_(printf)("%s\n", soname);
4476
4477# if defined(VGO_linux)
sewardj651cfa42010-01-11 13:02:19 +00004478 if (VG_STREQ(soname, VG_U_LD_LINUX_SO_3)) return True;
sewardja0eee322009-07-31 08:46:35 +00004479 if (VG_STREQ(soname, VG_U_LD_LINUX_SO_2)) return True;
4480 if (VG_STREQ(soname, VG_U_LD_LINUX_X86_64_SO_2)) return True;
4481 if (VG_STREQ(soname, VG_U_LD64_SO_1)) return True;
carll582d5822014-08-07 23:35:54 +00004482 if (VG_STREQ(soname, VG_U_LD64_SO_2)) return True;
sewardja0eee322009-07-31 08:46:35 +00004483 if (VG_STREQ(soname, VG_U_LD_SO_1)) return True;
sewardjdcd90512014-08-30 19:21:48 +00004484 if (VG_STREQ(soname, VG_U_LD_LINUX_AARCH64_SO_1)) return True;
mjw4fa71082014-09-01 15:29:55 +00004485 if (VG_STREQ(soname, VG_U_LD_LINUX_ARMHF_SO_3)) return True;
sewardja0eee322009-07-31 08:46:35 +00004486# elif defined(VGO_darwin)
4487 if (VG_STREQ(soname, VG_U_DYLD)) return True;
4488# else
4489# error "Unsupported OS"
4490# endif
4491 return False;
4492}
4493
sewardjb4112022007-11-09 22:49:28 +00004494static
4495IRSB* hg_instrument ( VgCallbackClosure* closure,
4496 IRSB* bbIn,
florian3c0c9472014-09-24 12:06:55 +00004497 const VexGuestLayout* layout,
4498 const VexGuestExtents* vge,
4499 const VexArchInfo* archinfo_host,
sewardjb4112022007-11-09 22:49:28 +00004500 IRType gWordTy, IRType hWordTy )
4501{
sewardj1c0ce7a2009-07-01 08:10:49 +00004502 Int i;
4503 IRSB* bbOut;
florianf466eef2015-01-02 17:32:40 +00004504 Addr cia; /* address of current insn */
sewardj1c0ce7a2009-07-01 08:10:49 +00004505 IRStmt* st;
sewardja0eee322009-07-31 08:46:35 +00004506 Bool inLDSO = False;
florianf466eef2015-01-02 17:32:40 +00004507 Addr inLDSOmask4K = 1; /* mismatches on first check */
sewardjb4112022007-11-09 22:49:28 +00004508
sewardjffce8152011-06-24 10:09:41 +00004509 const Int goff_sp = layout->offset_SP;
4510
sewardjb4112022007-11-09 22:49:28 +00004511 if (gWordTy != hWordTy) {
4512 /* We don't currently support this case. */
4513 VG_(tool_panic)("host/guest word size mismatch");
4514 }
4515
sewardja0eee322009-07-31 08:46:35 +00004516 if (VKI_PAGE_SIZE < 4096 || VG_(log2)(VKI_PAGE_SIZE) == -1) {
4517 VG_(tool_panic)("implausible or too-small VKI_PAGE_SIZE");
4518 }
4519
sewardjb4112022007-11-09 22:49:28 +00004520 /* Set up BB */
4521 bbOut = emptyIRSB();
4522 bbOut->tyenv = deepCopyIRTypeEnv(bbIn->tyenv);
4523 bbOut->next = deepCopyIRExpr(bbIn->next);
4524 bbOut->jumpkind = bbIn->jumpkind;
sewardj291849f2012-04-20 23:58:55 +00004525 bbOut->offsIP = bbIn->offsIP;
sewardjb4112022007-11-09 22:49:28 +00004526
4527 // Copy verbatim any IR preamble preceding the first IMark
4528 i = 0;
4529 while (i < bbIn->stmts_used && bbIn->stmts[i]->tag != Ist_IMark) {
4530 addStmtToIRSB( bbOut, bbIn->stmts[i] );
4531 i++;
4532 }
4533
sewardj1c0ce7a2009-07-01 08:10:49 +00004534 // Get the first statement, and initial cia from it
4535 tl_assert(bbIn->stmts_used > 0);
4536 tl_assert(i < bbIn->stmts_used);
4537 st = bbIn->stmts[i];
4538 tl_assert(Ist_IMark == st->tag);
4539 cia = st->Ist.IMark.addr;
4540 st = NULL;
4541
sewardjb4112022007-11-09 22:49:28 +00004542 for (/*use current i*/; i < bbIn->stmts_used; i++) {
sewardj1c0ce7a2009-07-01 08:10:49 +00004543 st = bbIn->stmts[i];
sewardjb4112022007-11-09 22:49:28 +00004544 tl_assert(st);
4545 tl_assert(isFlatIRStmt(st));
4546 switch (st->tag) {
4547 case Ist_NoOp:
4548 case Ist_AbiHint:
4549 case Ist_Put:
4550 case Ist_PutI:
sewardjb4112022007-11-09 22:49:28 +00004551 case Ist_Exit:
4552 /* None of these can contain any memory references. */
4553 break;
4554
sewardj1c0ce7a2009-07-01 08:10:49 +00004555 case Ist_IMark:
4556 /* no mem refs, but note the insn address. */
4557 cia = st->Ist.IMark.addr;
sewardja0eee322009-07-31 08:46:35 +00004558 /* Don't instrument the dynamic linker. It generates a
4559 lot of races which we just expensively suppress, so
4560 it's pointless.
4561
4562 Avoid flooding is_in_dynamic_linker_shared_object with
4563 requests by only checking at transitions between 4K
4564 pages. */
florianf466eef2015-01-02 17:32:40 +00004565 if ((cia & ~(Addr)0xFFF) != inLDSOmask4K) {
4566 if (0) VG_(printf)("NEW %#lx\n", cia);
4567 inLDSOmask4K = cia & ~(Addr)0xFFF;
sewardja0eee322009-07-31 08:46:35 +00004568 inLDSO = is_in_dynamic_linker_shared_object(cia);
4569 } else {
florianf466eef2015-01-02 17:32:40 +00004570 if (0) VG_(printf)("old %#lx\n", cia);
sewardja0eee322009-07-31 08:46:35 +00004571 }
sewardj1c0ce7a2009-07-01 08:10:49 +00004572 break;
4573
sewardjb4112022007-11-09 22:49:28 +00004574 case Ist_MBE:
sewardjf98e1c02008-10-25 16:22:41 +00004575 switch (st->Ist.MBE.event) {
4576 case Imbe_Fence:
sewardj2b9232a2014-10-11 13:54:52 +00004577 case Imbe_CancelReservation:
sewardjf98e1c02008-10-25 16:22:41 +00004578 break; /* not interesting */
sewardjf98e1c02008-10-25 16:22:41 +00004579 default:
4580 goto unhandled;
4581 }
sewardjb4112022007-11-09 22:49:28 +00004582 break;
4583
sewardj1c0ce7a2009-07-01 08:10:49 +00004584 case Ist_CAS: {
4585 /* Atomic read-modify-write cycle. Just pretend it's a
4586 read. */
4587 IRCAS* cas = st->Ist.CAS.details;
sewardj23f12002009-07-24 08:45:08 +00004588 Bool isDCAS = cas->oldHi != IRTemp_INVALID;
4589 if (isDCAS) {
4590 tl_assert(cas->expdHi);
4591 tl_assert(cas->dataHi);
4592 } else {
4593 tl_assert(!cas->expdHi);
4594 tl_assert(!cas->dataHi);
4595 }
4596 /* Just be boring about it. */
sewardja0eee322009-07-31 08:46:35 +00004597 if (!inLDSO) {
4598 instrument_mem_access(
4599 bbOut,
4600 cas->addr,
4601 (isDCAS ? 2 : 1)
4602 * sizeofIRType(typeOfIRExpr(bbIn->tyenv, cas->dataLo)),
4603 False/*!isStore*/,
sewardjcafe5052013-01-17 14:24:35 +00004604 sizeofIRType(hWordTy), goff_sp,
4605 NULL/*no-guard*/
sewardja0eee322009-07-31 08:46:35 +00004606 );
4607 }
sewardj1c0ce7a2009-07-01 08:10:49 +00004608 break;
4609 }
4610
sewardjdb5907d2009-11-26 17:20:21 +00004611 case Ist_LLSC: {
4612 /* We pretend store-conditionals don't exist, viz, ignore
4613 them. Whereas load-linked's are treated the same as
4614 normal loads. */
4615 IRType dataTy;
4616 if (st->Ist.LLSC.storedata == NULL) {
4617 /* LL */
4618 dataTy = typeOfIRTemp(bbIn->tyenv, st->Ist.LLSC.result);
sewardja0eee322009-07-31 08:46:35 +00004619 if (!inLDSO) {
sewardjdb5907d2009-11-26 17:20:21 +00004620 instrument_mem_access(
4621 bbOut,
4622 st->Ist.LLSC.addr,
4623 sizeofIRType(dataTy),
4624 False/*!isStore*/,
sewardjcafe5052013-01-17 14:24:35 +00004625 sizeofIRType(hWordTy), goff_sp,
4626 NULL/*no-guard*/
sewardja0eee322009-07-31 08:46:35 +00004627 );
4628 }
sewardjdb5907d2009-11-26 17:20:21 +00004629 } else {
4630 /* SC */
4631 /*ignore */
4632 }
4633 break;
4634 }
4635
4636 case Ist_Store:
sewardjdb5907d2009-11-26 17:20:21 +00004637 if (!inLDSO) {
4638 instrument_mem_access(
4639 bbOut,
4640 st->Ist.Store.addr,
4641 sizeofIRType(typeOfIRExpr(bbIn->tyenv, st->Ist.Store.data)),
4642 True/*isStore*/,
sewardjcafe5052013-01-17 14:24:35 +00004643 sizeofIRType(hWordTy), goff_sp,
4644 NULL/*no-guard*/
sewardjdb5907d2009-11-26 17:20:21 +00004645 );
sewardj1c0ce7a2009-07-01 08:10:49 +00004646 }
njnb83caf22009-05-25 01:47:56 +00004647 break;
sewardjb4112022007-11-09 22:49:28 +00004648
sewardjcafe5052013-01-17 14:24:35 +00004649 case Ist_StoreG: {
4650 IRStoreG* sg = st->Ist.StoreG.details;
4651 IRExpr* data = sg->data;
4652 IRExpr* addr = sg->addr;
4653 IRType type = typeOfIRExpr(bbIn->tyenv, data);
4654 tl_assert(type != Ity_INVALID);
4655 instrument_mem_access( bbOut, addr, sizeofIRType(type),
4656 True/*isStore*/,
4657 sizeofIRType(hWordTy),
4658 goff_sp, sg->guard );
4659 break;
4660 }
4661
4662 case Ist_LoadG: {
4663 IRLoadG* lg = st->Ist.LoadG.details;
4664 IRType type = Ity_INVALID; /* loaded type */
4665 IRType typeWide = Ity_INVALID; /* after implicit widening */
4666 IRExpr* addr = lg->addr;
4667 typeOfIRLoadGOp(lg->cvt, &typeWide, &type);
4668 tl_assert(type != Ity_INVALID);
4669 instrument_mem_access( bbOut, addr, sizeofIRType(type),
4670 False/*!isStore*/,
4671 sizeofIRType(hWordTy),
4672 goff_sp, lg->guard );
4673 break;
4674 }
4675
sewardjb4112022007-11-09 22:49:28 +00004676 case Ist_WrTmp: {
4677 IRExpr* data = st->Ist.WrTmp.data;
4678 if (data->tag == Iex_Load) {
sewardja0eee322009-07-31 08:46:35 +00004679 if (!inLDSO) {
4680 instrument_mem_access(
4681 bbOut,
4682 data->Iex.Load.addr,
4683 sizeofIRType(data->Iex.Load.ty),
4684 False/*!isStore*/,
sewardjcafe5052013-01-17 14:24:35 +00004685 sizeofIRType(hWordTy), goff_sp,
4686 NULL/*no-guard*/
sewardja0eee322009-07-31 08:46:35 +00004687 );
4688 }
sewardjb4112022007-11-09 22:49:28 +00004689 }
4690 break;
4691 }
4692
4693 case Ist_Dirty: {
4694 Int dataSize;
4695 IRDirty* d = st->Ist.Dirty.details;
4696 if (d->mFx != Ifx_None) {
4697 /* This dirty helper accesses memory. Collect the
4698 details. */
4699 tl_assert(d->mAddr != NULL);
4700 tl_assert(d->mSize != 0);
4701 dataSize = d->mSize;
4702 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify) {
sewardja0eee322009-07-31 08:46:35 +00004703 if (!inLDSO) {
4704 instrument_mem_access(
4705 bbOut, d->mAddr, dataSize, False/*!isStore*/,
sewardjcafe5052013-01-17 14:24:35 +00004706 sizeofIRType(hWordTy), goff_sp, NULL/*no-guard*/
sewardja0eee322009-07-31 08:46:35 +00004707 );
4708 }
sewardjb4112022007-11-09 22:49:28 +00004709 }
4710 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify) {
sewardja0eee322009-07-31 08:46:35 +00004711 if (!inLDSO) {
4712 instrument_mem_access(
4713 bbOut, d->mAddr, dataSize, True/*isStore*/,
sewardjcafe5052013-01-17 14:24:35 +00004714 sizeofIRType(hWordTy), goff_sp, NULL/*no-guard*/
sewardja0eee322009-07-31 08:46:35 +00004715 );
4716 }
sewardjb4112022007-11-09 22:49:28 +00004717 }
4718 } else {
4719 tl_assert(d->mAddr == NULL);
4720 tl_assert(d->mSize == 0);
4721 }
4722 break;
4723 }
4724
4725 default:
sewardjf98e1c02008-10-25 16:22:41 +00004726 unhandled:
4727 ppIRStmt(st);
sewardjb4112022007-11-09 22:49:28 +00004728 tl_assert(0);
4729
4730 } /* switch (st->tag) */
4731
4732 addStmtToIRSB( bbOut, st );
4733 } /* iterate over bbIn->stmts */
4734
4735 return bbOut;
4736}
4737
sewardjffce8152011-06-24 10:09:41 +00004738#undef binop
4739#undef mkexpr
4740#undef mkU32
4741#undef mkU64
4742#undef assign
4743
sewardjb4112022007-11-09 22:49:28 +00004744
4745/*----------------------------------------------------------------*/
4746/*--- Client requests ---*/
4747/*----------------------------------------------------------------*/
4748
4749/* Sheesh. Yet another goddam finite map. */
4750static WordFM* map_pthread_t_to_Thread = NULL; /* pthread_t -> Thread* */
4751
4752static void map_pthread_t_to_Thread_INIT ( void ) {
4753 if (UNLIKELY(map_pthread_t_to_Thread == NULL)) {
sewardjf98e1c02008-10-25 16:22:41 +00004754 map_pthread_t_to_Thread = VG_(newFM)( HG_(zalloc), "hg.mpttT.1",
4755 HG_(free), NULL );
sewardjb4112022007-11-09 22:49:28 +00004756 }
4757}
4758
philipped40aff52014-06-16 20:00:14 +00004759/* A list of Ada dependent tasks and their masters. Used for implementing
4760 the Ada task termination semantic as implemented by the
4761 gcc gnat Ada runtime. */
4762typedef
4763 struct {
4764 void* dependent; // Ada Task Control Block of the Dependent
4765 void* master; // ATCB of the master
4766 Word master_level; // level of dependency between master and dependent
4767 Thread* hg_dependent; // helgrind Thread* for dependent task.
4768 }
4769 GNAT_dmml;
4770static XArray* gnat_dmmls; /* of GNAT_dmml */
4771static void gnat_dmmls_INIT (void)
4772{
4773 if (UNLIKELY(gnat_dmmls == NULL)) {
4774 gnat_dmmls = VG_(newXA) (HG_(zalloc), "hg.gnat_md.1",
4775 HG_(free),
4776 sizeof(GNAT_dmml) );
4777 }
4778}
philippef5774342014-05-03 11:12:50 +00004779static void print_monitor_help ( void )
4780{
4781 VG_(gdb_printf)
4782 (
4783"\n"
4784"helgrind monitor commands:\n"
philippef5774342014-05-03 11:12:50 +00004785" info locks : show list of locks and their status\n"
4786"\n");
4787}
4788
4789/* return True if request recognised, False otherwise */
4790static Bool handle_gdb_monitor_command (ThreadId tid, HChar *req)
4791{
philippef5774342014-05-03 11:12:50 +00004792 HChar* wcmd;
4793 HChar s[VG_(strlen(req))]; /* copy for strtok_r */
4794 HChar *ssaveptr;
4795 Int kwdid;
4796
4797 VG_(strcpy) (s, req);
4798
4799 wcmd = VG_(strtok_r) (s, " ", &ssaveptr);
4800 /* NB: if possible, avoid introducing a new command below which
4801 starts with the same first letter(s) as an already existing
4802 command. This ensures a shorter abbreviation for the user. */
4803 switch (VG_(keyword_id)
philippe07c08522014-05-14 20:39:27 +00004804 ("help info",
philippef5774342014-05-03 11:12:50 +00004805 wcmd, kwd_report_duplicated_matches)) {
4806 case -2: /* multiple matches */
4807 return True;
4808 case -1: /* not found */
4809 return False;
4810 case 0: /* help */
4811 print_monitor_help();
4812 return True;
4813 case 1: /* info */
philippef5774342014-05-03 11:12:50 +00004814 wcmd = VG_(strtok_r) (NULL, " ", &ssaveptr);
4815 switch (kwdid = VG_(keyword_id)
4816 ("locks",
4817 wcmd, kwd_report_all)) {
4818 case -2:
4819 case -1:
4820 break;
4821 case 0: // locks
4822 {
4823 Int i;
4824 Lock* lk;
4825 for (i = 0, lk = admin_locks; lk; i++, lk = lk->admin_next) {
4826 pp_Lock(0, lk,
4827 True /* show_lock_addrdescr */,
4828 False /* show_internal_data */);
4829 }
4830 if (i == 0)
4831 VG_(gdb_printf) ("no locks\n");
4832 }
4833 break;
4834 default:
4835 tl_assert(0);
4836 }
4837 return True;
philippef5774342014-05-03 11:12:50 +00004838 default:
4839 tl_assert(0);
4840 return False;
4841 }
4842}
sewardjb4112022007-11-09 22:49:28 +00004843
4844static
4845Bool hg_handle_client_request ( ThreadId tid, UWord* args, UWord* ret)
4846{
philippef5774342014-05-03 11:12:50 +00004847 if (!VG_IS_TOOL_USERREQ('H','G',args[0])
4848 && VG_USERREQ__GDB_MONITOR_COMMAND != args[0])
sewardjb4112022007-11-09 22:49:28 +00004849 return False;
4850
4851 /* Anything that gets past the above check is one of ours, so we
4852 should be able to handle it. */
4853
4854 /* default, meaningless return value, unless otherwise set */
4855 *ret = 0;
4856
4857 switch (args[0]) {
4858
4859 /* --- --- User-visible client requests --- --- */
4860
4861 case VG_USERREQ__HG_CLEAN_MEMORY:
barta0b6b2c2008-07-07 06:49:24 +00004862 if (0) VG_(printf)("VG_USERREQ__HG_CLEAN_MEMORY(%#lx,%ld)\n",
sewardjb4112022007-11-09 22:49:28 +00004863 args[1], args[2]);
4864 /* Call die_mem to (expensively) tidy up properly, if there
sewardjf98e1c02008-10-25 16:22:41 +00004865 are any held locks etc in the area. Calling evh__die_mem
4866 and then evh__new_mem is a bit inefficient; probably just
4867 the latter would do. */
sewardjb4112022007-11-09 22:49:28 +00004868 if (args[2] > 0) { /* length */
4869 evh__die_mem(args[1], args[2]);
4870 /* and then set it to New */
4871 evh__new_mem(args[1], args[2]);
4872 }
4873 break;
4874
sewardjc8028ad2010-05-05 09:34:42 +00004875 case _VG_USERREQ__HG_CLEAN_MEMORY_HEAPBLOCK: {
4876 Addr payload = 0;
4877 SizeT pszB = 0;
4878 if (0) VG_(printf)("VG_USERREQ__HG_CLEAN_MEMORY_HEAPBLOCK(%#lx)\n",
4879 args[1]);
philippe0c9ac8d2014-07-18 00:03:58 +00004880 if (HG_(mm_find_containing_block)(NULL, NULL,
4881 &payload, &pszB, args[1])) {
sewardjc8028ad2010-05-05 09:34:42 +00004882 if (pszB > 0) {
4883 evh__die_mem(payload, pszB);
4884 evh__new_mem(payload, pszB);
4885 }
4886 *ret = pszB;
4887 } else {
4888 *ret = (UWord)-1;
4889 }
4890 break;
4891 }
4892
sewardj406bac82010-03-03 23:03:40 +00004893 case _VG_USERREQ__HG_ARANGE_MAKE_UNTRACKED:
4894 if (0) VG_(printf)("HG_ARANGE_MAKE_UNTRACKED(%#lx,%ld)\n",
4895 args[1], args[2]);
4896 if (args[2] > 0) { /* length */
4897 evh__untrack_mem(args[1], args[2]);
4898 }
4899 break;
4900
4901 case _VG_USERREQ__HG_ARANGE_MAKE_TRACKED:
4902 if (0) VG_(printf)("HG_ARANGE_MAKE_TRACKED(%#lx,%ld)\n",
4903 args[1], args[2]);
4904 if (args[2] > 0) { /* length */
4905 evh__new_mem(args[1], args[2]);
4906 }
4907 break;
4908
philippef54cb662015-05-10 22:19:31 +00004909 case _VG_USERREQ__HG_GET_ABITS:
4910 if (0) VG_(printf)("HG_GET_ABITS(%#lx,%#lx,%ld)\n",
4911 args[1], args[2], args[3]);
4912 UChar *zzabit = (UChar *) args[2];
4913 if (zzabit == NULL
4914 || VG_(am_is_valid_for_client)((Addr)zzabit, (SizeT)args[3],
4915 VKI_PROT_READ|VKI_PROT_WRITE))
4916 *ret = (UWord) libhb_srange_get_abits ((Addr) args[1],
4917 (UChar*) args[2],
4918 (SizeT) args[3]);
4919 else
4920 *ret = -1;
4921 break;
4922
sewardjb4112022007-11-09 22:49:28 +00004923 /* --- --- Client requests for Helgrind's use only --- --- */
4924
4925 /* Some thread is telling us its pthread_t value. Record the
4926 binding between that and the associated Thread*, so we can
4927 later find the Thread* again when notified of a join by the
4928 thread. */
4929 case _VG_USERREQ__HG_SET_MY_PTHREAD_T: {
4930 Thread* my_thr = NULL;
4931 if (0)
4932 VG_(printf)("SET_MY_PTHREAD_T (tid %d): pthread_t = %p\n", (Int)tid,
4933 (void*)args[1]);
4934 map_pthread_t_to_Thread_INIT();
4935 my_thr = map_threads_maybe_lookup( tid );
4936 /* This assertion should hold because the map_threads (tid to
4937 Thread*) binding should have been made at the point of
4938 low-level creation of this thread, which should have
4939 happened prior to us getting this client request for it.
4940 That's because this client request is sent from
4941 client-world from the 'thread_wrapper' function, which
4942 only runs once the thread has been low-level created. */
4943 tl_assert(my_thr != NULL);
4944 /* So now we know that (pthread_t)args[1] is associated with
4945 (Thread*)my_thr. Note that down. */
4946 if (0)
4947 VG_(printf)("XXXX: bind pthread_t %p to Thread* %p\n",
4948 (void*)args[1], (void*)my_thr );
florian6bf37262012-10-21 03:23:36 +00004949 VG_(addToFM)( map_pthread_t_to_Thread, (UWord)args[1], (UWord)my_thr );
sewardjb4112022007-11-09 22:49:28 +00004950 break;
4951 }
4952
4953 case _VG_USERREQ__HG_PTH_API_ERROR: {
4954 Thread* my_thr = NULL;
4955 map_pthread_t_to_Thread_INIT();
4956 my_thr = map_threads_maybe_lookup( tid );
4957 tl_assert(my_thr); /* See justification above in SET_MY_PTHREAD_T */
sewardjf98e1c02008-10-25 16:22:41 +00004958 HG_(record_error_PthAPIerror)(
florian6bf37262012-10-21 03:23:36 +00004959 my_thr, (HChar*)args[1], (UWord)args[2], (HChar*)args[3] );
sewardjb4112022007-11-09 22:49:28 +00004960 break;
4961 }
4962
4963 /* This thread (tid) has completed a join with the quitting
4964 thread whose pthread_t is in args[1]. */
4965 case _VG_USERREQ__HG_PTHREAD_JOIN_POST: {
4966 Thread* thr_q = NULL; /* quitter Thread* */
4967 Bool found = False;
4968 if (0)
4969 VG_(printf)("NOTIFY_JOIN_COMPLETE (tid %d): quitter = %p\n", (Int)tid,
4970 (void*)args[1]);
4971 map_pthread_t_to_Thread_INIT();
sewardj896f6f92008-08-19 08:38:52 +00004972 found = VG_(lookupFM)( map_pthread_t_to_Thread,
florian6bf37262012-10-21 03:23:36 +00004973 NULL, (UWord*)&thr_q, (UWord)args[1] );
sewardjb4112022007-11-09 22:49:28 +00004974 /* Can this fail? It would mean that our pthread_join
4975 wrapper observed a successful join on args[1] yet that
4976 thread never existed (or at least, it never lodged an
4977 entry in the mapping (via SET_MY_PTHREAD_T)). Which
4978 sounds like a bug in the threads library. */
4979 // FIXME: get rid of this assertion; handle properly
4980 tl_assert(found);
4981 if (found) {
4982 if (0)
4983 VG_(printf)(".................... quitter Thread* = %p\n",
4984 thr_q);
4985 evh__HG_PTHREAD_JOIN_POST( tid, thr_q );
4986 }
4987 break;
4988 }
4989
philipped40aff52014-06-16 20:00:14 +00004990 /* This thread (tid) is informing us of its master. */
4991 case _VG_USERREQ__HG_GNAT_MASTER_HOOK: {
4992 GNAT_dmml dmml;
4993 dmml.dependent = (void*)args[1];
4994 dmml.master = (void*)args[2];
4995 dmml.master_level = (Word)args[3];
4996 dmml.hg_dependent = map_threads_maybe_lookup( tid );
4997 tl_assert(dmml.hg_dependent);
4998
4999 if (0)
5000 VG_(printf)("HG_GNAT_MASTER_HOOK (tid %d): "
5001 "dependent = %p master = %p master_level = %ld"
5002 " dependent Thread* = %p\n",
5003 (Int)tid, dmml.dependent, dmml.master, dmml.master_level,
5004 dmml.hg_dependent);
5005 gnat_dmmls_INIT();
5006 VG_(addToXA) (gnat_dmmls, &dmml);
5007 break;
5008 }
5009
5010 /* This thread (tid) is informing us that it has completed a
5011 master. */
5012 case _VG_USERREQ__HG_GNAT_MASTER_COMPLETED_HOOK: {
5013 Word n;
5014 const Thread *stayer = map_threads_maybe_lookup( tid );
5015 const void *master = (void*)args[1];
5016 const Word master_level = (Word) args[2];
5017 tl_assert(stayer);
5018
5019 if (0)
5020 VG_(printf)("HG_GNAT_MASTER_COMPLETED_HOOK (tid %d): "
5021 "self_id = %p master_level = %ld Thread* = %p\n",
5022 (Int)tid, master, master_level, stayer);
5023
5024 gnat_dmmls_INIT();
5025 /* Reverse loop on the array, simulating a pthread_join for
5026 the Dependent tasks of the completed master, and removing
5027 them from the array. */
5028 for (n = VG_(sizeXA) (gnat_dmmls) - 1; n >= 0; n--) {
5029 GNAT_dmml *dmml = (GNAT_dmml*) VG_(indexXA)(gnat_dmmls, n);
5030 if (dmml->master == master
5031 && dmml->master_level == master_level) {
5032 if (0)
5033 VG_(printf)("quitter %p dependency to stayer %p\n",
5034 dmml->hg_dependent->hbthr, stayer->hbthr);
5035 tl_assert(dmml->hg_dependent->hbthr != stayer->hbthr);
5036 generate_quitter_stayer_dependence (dmml->hg_dependent->hbthr,
5037 stayer->hbthr);
5038 VG_(removeIndexXA) (gnat_dmmls, n);
5039 }
5040 }
5041 break;
5042 }
5043
sewardjb4112022007-11-09 22:49:28 +00005044 /* EXPOSITION only: by intercepting lock init events we can show
5045 the user where the lock was initialised, rather than only
5046 being able to show where it was first locked. Intercepting
5047 lock initialisations is not necessary for the basic operation
5048 of the race checker. */
5049 case _VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST:
5050 evh__HG_PTHREAD_MUTEX_INIT_POST( tid, (void*)args[1], args[2] );
5051 break;
5052
sewardjc02f6c42013-10-14 13:51:25 +00005053 /* mutex=arg[1], mutex_is_init=arg[2] */
sewardjb4112022007-11-09 22:49:28 +00005054 case _VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE:
sewardjc02f6c42013-10-14 13:51:25 +00005055 evh__HG_PTHREAD_MUTEX_DESTROY_PRE( tid, (void*)args[1], args[2] != 0 );
sewardjb4112022007-11-09 22:49:28 +00005056 break;
5057
5058 case _VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE: // pth_mx_t*
5059 evh__HG_PTHREAD_MUTEX_UNLOCK_PRE( tid, (void*)args[1] );
5060 break;
5061
5062 case _VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST: // pth_mx_t*
5063 evh__HG_PTHREAD_MUTEX_UNLOCK_POST( tid, (void*)args[1] );
5064 break;
5065
5066 case _VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE: // pth_mx_t*, Word
5067 evh__HG_PTHREAD_MUTEX_LOCK_PRE( tid, (void*)args[1], args[2] );
5068 break;
5069
5070 case _VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST: // pth_mx_t*
5071 evh__HG_PTHREAD_MUTEX_LOCK_POST( tid, (void*)args[1] );
5072 break;
5073
5074 /* This thread is about to do pthread_cond_signal on the
5075 pthread_cond_t* in arg[1]. Ditto pthread_cond_broadcast. */
5076 case _VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE:
5077 case _VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE:
5078 evh__HG_PTHREAD_COND_SIGNAL_PRE( tid, (void*)args[1] );
5079 break;
5080
5081 /* Entry into pthread_cond_wait, cond=arg[1], mutex=arg[2].
5082 Returns a flag indicating whether or not the mutex is believed to be
5083 valid for this operation. */
5084 case _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE: {
5085 Bool mutex_is_valid
5086 = evh__HG_PTHREAD_COND_WAIT_PRE( tid, (void*)args[1],
5087 (void*)args[2] );
5088 *ret = mutex_is_valid ? 1 : 0;
5089 break;
5090 }
5091
philippe19dfe032013-03-24 20:10:23 +00005092 /* Thread successfully completed pthread_cond_init:
5093 cond=arg[1], cond_attr=arg[2] */
5094 case _VG_USERREQ__HG_PTHREAD_COND_INIT_POST:
5095 evh__HG_PTHREAD_COND_INIT_POST( tid,
5096 (void*)args[1], (void*)args[2] );
5097 break;
5098
sewardjc02f6c42013-10-14 13:51:25 +00005099 /* cond=arg[1], cond_is_init=arg[2] */
sewardjf98e1c02008-10-25 16:22:41 +00005100 case _VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE:
sewardjc02f6c42013-10-14 13:51:25 +00005101 evh__HG_PTHREAD_COND_DESTROY_PRE( tid, (void*)args[1], args[2] != 0 );
sewardjf98e1c02008-10-25 16:22:41 +00005102 break;
5103
sewardjb4112022007-11-09 22:49:28 +00005104 /* Thread successfully completed pthread_cond_wait, cond=arg[1],
5105 mutex=arg[2] */
5106 case _VG_USERREQ__HG_PTHREAD_COND_WAIT_POST:
5107 evh__HG_PTHREAD_COND_WAIT_POST( tid,
sewardjff427c92013-10-14 12:13:52 +00005108 (void*)args[1], (void*)args[2],
5109 (Bool)args[3] );
sewardjb4112022007-11-09 22:49:28 +00005110 break;
5111
5112 case _VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST:
5113 evh__HG_PTHREAD_RWLOCK_INIT_POST( tid, (void*)args[1] );
5114 break;
5115
5116 case _VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE:
5117 evh__HG_PTHREAD_RWLOCK_DESTROY_PRE( tid, (void*)args[1] );
5118 break;
5119
sewardj789c3c52008-02-25 12:10:07 +00005120 /* rwlock=arg[1], isW=arg[2], isTryLock=arg[3] */
sewardjb4112022007-11-09 22:49:28 +00005121 case _VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE:
sewardj789c3c52008-02-25 12:10:07 +00005122 evh__HG_PTHREAD_RWLOCK_LOCK_PRE( tid, (void*)args[1],
5123 args[2], args[3] );
sewardjb4112022007-11-09 22:49:28 +00005124 break;
5125
5126 /* rwlock=arg[1], isW=arg[2] */
5127 case _VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST:
5128 evh__HG_PTHREAD_RWLOCK_LOCK_POST( tid, (void*)args[1], args[2] );
5129 break;
5130
5131 case _VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE:
5132 evh__HG_PTHREAD_RWLOCK_UNLOCK_PRE( tid, (void*)args[1] );
5133 break;
5134
5135 case _VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST:
5136 evh__HG_PTHREAD_RWLOCK_UNLOCK_POST( tid, (void*)args[1] );
5137 break;
5138
sewardj11e352f2007-11-30 11:11:02 +00005139 case _VG_USERREQ__HG_POSIX_SEM_INIT_POST: /* sem_t*, unsigned long */
5140 evh__HG_POSIX_SEM_INIT_POST( tid, (void*)args[1], args[2] );
sewardjb4112022007-11-09 22:49:28 +00005141 break;
5142
sewardj11e352f2007-11-30 11:11:02 +00005143 case _VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE: /* sem_t* */
5144 evh__HG_POSIX_SEM_DESTROY_PRE( tid, (void*)args[1] );
sewardjb4112022007-11-09 22:49:28 +00005145 break;
5146
sewardj11e352f2007-11-30 11:11:02 +00005147 case _VG_USERREQ__HG_POSIX_SEM_POST_PRE: /* sem_t* */
5148 evh__HG_POSIX_SEM_POST_PRE( tid, (void*)args[1] );
5149 break;
5150
5151 case _VG_USERREQ__HG_POSIX_SEM_WAIT_POST: /* sem_t* */
5152 evh__HG_POSIX_SEM_WAIT_POST( tid, (void*)args[1] );
sewardjb4112022007-11-09 22:49:28 +00005153 break;
5154
sewardj9f569b72008-11-13 13:33:09 +00005155 case _VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE:
sewardj406bac82010-03-03 23:03:40 +00005156 /* pth_bar_t*, ulong count, ulong resizable */
5157 evh__HG_PTHREAD_BARRIER_INIT_PRE( tid, (void*)args[1],
5158 args[2], args[3] );
5159 break;
5160
5161 case _VG_USERREQ__HG_PTHREAD_BARRIER_RESIZE_PRE:
5162 /* pth_bar_t*, ulong newcount */
5163 evh__HG_PTHREAD_BARRIER_RESIZE_PRE ( tid, (void*)args[1],
5164 args[2] );
sewardj9f569b72008-11-13 13:33:09 +00005165 break;
5166
5167 case _VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE:
5168 /* pth_bar_t* */
5169 evh__HG_PTHREAD_BARRIER_WAIT_PRE( tid, (void*)args[1] );
5170 break;
5171
5172 case _VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE:
5173 /* pth_bar_t* */
5174 evh__HG_PTHREAD_BARRIER_DESTROY_PRE( tid, (void*)args[1] );
5175 break;
sewardjb4112022007-11-09 22:49:28 +00005176
sewardj5a644da2009-08-11 10:35:58 +00005177 case _VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE:
5178 /* pth_spinlock_t* */
5179 evh__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE( tid, (void*)args[1] );
5180 break;
5181
5182 case _VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST:
5183 /* pth_spinlock_t* */
5184 evh__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST( tid, (void*)args[1] );
5185 break;
5186
5187 case _VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE:
5188 /* pth_spinlock_t*, Word */
5189 evh__HG_PTHREAD_SPIN_LOCK_PRE( tid, (void*)args[1], args[2] );
5190 break;
5191
5192 case _VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST:
5193 /* pth_spinlock_t* */
5194 evh__HG_PTHREAD_SPIN_LOCK_POST( tid, (void*)args[1] );
5195 break;
5196
5197 case _VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE:
5198 /* pth_spinlock_t* */
5199 evh__HG_PTHREAD_SPIN_DESTROY_PRE( tid, (void*)args[1] );
5200 break;
5201
sewardjed2e72e2009-08-14 11:08:24 +00005202 case _VG_USERREQ__HG_CLIENTREQ_UNIMP: {
florian19f91bb2012-11-10 22:29:54 +00005203 /* HChar* who */
sewardjed2e72e2009-08-14 11:08:24 +00005204 HChar* who = (HChar*)args[1];
5205 HChar buf[50 + 50];
5206 Thread* thr = map_threads_maybe_lookup( tid );
5207 tl_assert( thr ); /* I must be mapped */
5208 tl_assert( who );
5209 tl_assert( VG_(strlen)(who) <= 50 );
5210 VG_(sprintf)(buf, "Unimplemented client request macro \"%s\"", who );
5211 /* record_error_Misc strdup's buf, so this is safe: */
5212 HG_(record_error_Misc)( thr, buf );
5213 break;
5214 }
5215
5216 case _VG_USERREQ__HG_USERSO_SEND_PRE:
5217 /* UWord arbitrary-SO-tag */
5218 evh__HG_USERSO_SEND_PRE( tid, args[1] );
5219 break;
5220
5221 case _VG_USERREQ__HG_USERSO_RECV_POST:
5222 /* UWord arbitrary-SO-tag */
5223 evh__HG_USERSO_RECV_POST( tid, args[1] );
5224 break;
5225
sewardj6015d0e2011-03-11 19:10:48 +00005226 case _VG_USERREQ__HG_USERSO_FORGET_ALL:
5227 /* UWord arbitrary-SO-tag */
5228 evh__HG_USERSO_FORGET_ALL( tid, args[1] );
5229 break;
5230
philippef5774342014-05-03 11:12:50 +00005231 case VG_USERREQ__GDB_MONITOR_COMMAND: {
5232 Bool handled = handle_gdb_monitor_command (tid, (HChar*)args[1]);
5233 if (handled)
5234 *ret = 1;
5235 else
5236 *ret = 0;
5237 return handled;
5238 }
5239
sewardjb4112022007-11-09 22:49:28 +00005240 default:
5241 /* Unhandled Helgrind client request! */
sewardjf98e1c02008-10-25 16:22:41 +00005242 tl_assert2(0, "unhandled Helgrind client request 0x%lx",
5243 args[0]);
sewardjb4112022007-11-09 22:49:28 +00005244 }
5245
5246 return True;
5247}
5248
5249
5250/*----------------------------------------------------------------*/
sewardjb4112022007-11-09 22:49:28 +00005251/*--- Setup ---*/
5252/*----------------------------------------------------------------*/
5253
florian19f91bb2012-11-10 22:29:54 +00005254static Bool hg_process_cmd_line_option ( const HChar* arg )
sewardjb4112022007-11-09 22:49:28 +00005255{
florian19f91bb2012-11-10 22:29:54 +00005256 const HChar* tmp_str;
sewardjb4112022007-11-09 22:49:28 +00005257
njn83df0b62009-02-25 01:01:05 +00005258 if VG_BOOL_CLO(arg, "--track-lockorders",
5259 HG_(clo_track_lockorders)) {}
5260 else if VG_BOOL_CLO(arg, "--cmp-race-err-addrs",
5261 HG_(clo_cmp_race_err_addrs)) {}
sewardj23f12002009-07-24 08:45:08 +00005262
5263 else if VG_XACT_CLO(arg, "--history-level=none",
5264 HG_(clo_history_level), 0);
sewardjf3861392009-08-02 10:16:03 +00005265 else if VG_XACT_CLO(arg, "--history-level=approx",
sewardj23f12002009-07-24 08:45:08 +00005266 HG_(clo_history_level), 1);
5267 else if VG_XACT_CLO(arg, "--history-level=full",
5268 HG_(clo_history_level), 2);
sewardj849b0ed2008-12-21 10:43:10 +00005269
sewardjf585e482009-08-16 22:52:29 +00005270 /* If you change the 10k/30mill limits, remember to also change
sewardj849b0ed2008-12-21 10:43:10 +00005271 them in assertions at the top of event_map_maybe_GC. */
njn83df0b62009-02-25 01:01:05 +00005272 else if VG_BINT_CLO(arg, "--conflict-cache-size",
sewardjf585e482009-08-16 22:52:29 +00005273 HG_(clo_conflict_cache_size), 10*1000, 30*1000*1000) {}
sewardjb4112022007-11-09 22:49:28 +00005274
sewardj11e352f2007-11-30 11:11:02 +00005275 /* "stuvwx" --> stuvwx (binary) */
njn83df0b62009-02-25 01:01:05 +00005276 else if VG_STR_CLO(arg, "--hg-sanity-flags", tmp_str) {
sewardjb4112022007-11-09 22:49:28 +00005277 Int j;
sewardjb4112022007-11-09 22:49:28 +00005278
njn83df0b62009-02-25 01:01:05 +00005279 if (6 != VG_(strlen)(tmp_str)) {
sewardjb4112022007-11-09 22:49:28 +00005280 VG_(message)(Vg_UserMsg,
sewardj24118492009-07-15 14:50:02 +00005281 "--hg-sanity-flags argument must have 6 digits\n");
sewardjb4112022007-11-09 22:49:28 +00005282 return False;
5283 }
sewardj11e352f2007-11-30 11:11:02 +00005284 for (j = 0; j < 6; j++) {
njn83df0b62009-02-25 01:01:05 +00005285 if ('0' == tmp_str[j]) { /* do nothing */ }
5286 else if ('1' == tmp_str[j]) HG_(clo_sanity_flags) |= (1 << (6-1-j));
sewardjb4112022007-11-09 22:49:28 +00005287 else {
sewardj11e352f2007-11-30 11:11:02 +00005288 VG_(message)(Vg_UserMsg, "--hg-sanity-flags argument can "
sewardj24118492009-07-15 14:50:02 +00005289 "only contain 0s and 1s\n");
sewardjb4112022007-11-09 22:49:28 +00005290 return False;
5291 }
5292 }
sewardjf98e1c02008-10-25 16:22:41 +00005293 if (0) VG_(printf)("XXX sanity flags: 0x%lx\n", HG_(clo_sanity_flags));
sewardjb4112022007-11-09 22:49:28 +00005294 }
5295
sewardj622fe492011-03-11 21:06:59 +00005296 else if VG_BOOL_CLO(arg, "--free-is-write",
5297 HG_(clo_free_is_write)) {}
sewardjffce8152011-06-24 10:09:41 +00005298
5299 else if VG_XACT_CLO(arg, "--vts-pruning=never",
5300 HG_(clo_vts_pruning), 0);
5301 else if VG_XACT_CLO(arg, "--vts-pruning=auto",
5302 HG_(clo_vts_pruning), 1);
5303 else if VG_XACT_CLO(arg, "--vts-pruning=always",
5304 HG_(clo_vts_pruning), 2);
5305
5306 else if VG_BOOL_CLO(arg, "--check-stack-refs",
5307 HG_(clo_check_stack_refs)) {}
5308
sewardjb4112022007-11-09 22:49:28 +00005309 else
5310 return VG_(replacement_malloc_process_cmd_line_option)(arg);
5311
5312 return True;
5313}
5314
5315static void hg_print_usage ( void )
5316{
5317 VG_(printf)(
sewardj622fe492011-03-11 21:06:59 +00005318" --free-is-write=no|yes treat heap frees as writes [no]\n"
sewardj849b0ed2008-12-21 10:43:10 +00005319" --track-lockorders=no|yes show lock ordering errors? [yes]\n"
njnf6e8ca92009-08-07 02:18:00 +00005320" --history-level=none|approx|full [full]\n"
sewardjf3861392009-08-02 10:16:03 +00005321" full: show both stack traces for a data race (can be very slow)\n"
5322" approx: full trace for one thread, approx for the other (faster)\n"
5323" none: only show trace for one thread in a race (fastest)\n"
sewardj23f12002009-07-24 08:45:08 +00005324" --conflict-cache-size=N size of 'full' history cache [1000000]\n"
sewardjffce8152011-06-24 10:09:41 +00005325" --check-stack-refs=no|yes race-check reads and writes on the\n"
5326" main stack and thread stacks? [yes]\n"
sewardjb4112022007-11-09 22:49:28 +00005327 );
sewardjb4112022007-11-09 22:49:28 +00005328}
5329
5330static void hg_print_debug_usage ( void )
5331{
sewardjb4112022007-11-09 22:49:28 +00005332 VG_(printf)(" --cmp-race-err-addrs=no|yes are data addresses in "
5333 "race errors significant? [no]\n");
sewardj849b0ed2008-12-21 10:43:10 +00005334 VG_(printf)(" --hg-sanity-flags=<XXXXXX> sanity check "
sewardj11e352f2007-11-30 11:11:02 +00005335 " at events (X = 0|1) [000000]\n");
5336 VG_(printf)(" --hg-sanity-flags values:\n");
sewardj11e352f2007-11-30 11:11:02 +00005337 VG_(printf)(" 010000 after changes to "
sewardjb4112022007-11-09 22:49:28 +00005338 "lock-order-acquisition-graph\n");
sewardj11e352f2007-11-30 11:11:02 +00005339 VG_(printf)(" 001000 at memory accesses (NB: not currently used)\n");
5340 VG_(printf)(" 000100 at mem permission setting for "
sewardjb4112022007-11-09 22:49:28 +00005341 "ranges >= %d bytes\n", SCE_BIGRANGE_T);
sewardj11e352f2007-11-30 11:11:02 +00005342 VG_(printf)(" 000010 at lock/unlock events\n");
5343 VG_(printf)(" 000001 at thread create/join events\n");
sewardjffce8152011-06-24 10:09:41 +00005344 VG_(printf)(
5345" --vts-pruning=never|auto|always [auto]\n"
5346" never: is never done (may cause big space leaks in Helgrind)\n"
5347" auto: done just often enough to keep space usage under control\n"
5348" always: done after every VTS GC (mostly just a big time waster)\n"
5349 );
sewardjb4112022007-11-09 22:49:28 +00005350}
5351
philippe8587b542013-12-15 20:24:43 +00005352static void hg_print_stats (void)
5353{
5354
5355 if (1) {
5356 VG_(printf)("\n");
5357 HG_(ppWSUstats)( univ_lsets, "univ_lsets" );
5358 if (HG_(clo_track_lockorders)) {
5359 VG_(printf)("\n");
5360 HG_(ppWSUstats)( univ_laog, "univ_laog" );
5361 }
5362 }
5363
5364 //zz VG_(printf)("\n");
5365 //zz VG_(printf)(" hbefore: %'10lu queries\n", stats__hbefore_queries);
5366 //zz VG_(printf)(" hbefore: %'10lu cache 0 hits\n", stats__hbefore_cache0s);
5367 //zz VG_(printf)(" hbefore: %'10lu cache > 0 hits\n", stats__hbefore_cacheNs);
5368 //zz VG_(printf)(" hbefore: %'10lu graph searches\n", stats__hbefore_gsearches);
5369 //zz VG_(printf)(" hbefore: %'10lu of which slow\n",
5370 //zz stats__hbefore_gsearches - stats__hbefore_gsearchFs);
5371 //zz VG_(printf)(" hbefore: %'10lu stack high water mark\n",
5372 //zz stats__hbefore_stk_hwm);
5373 //zz VG_(printf)(" hbefore: %'10lu cache invals\n", stats__hbefore_invals);
5374 //zz VG_(printf)(" hbefore: %'10lu probes\n", stats__hbefore_probes);
5375
5376 VG_(printf)("\n");
5377 VG_(printf)(" locksets: %'8d unique lock sets\n",
5378 (Int)HG_(cardinalityWSU)( univ_lsets ));
5379 if (HG_(clo_track_lockorders)) {
5380 VG_(printf)(" univ_laog: %'8d unique lock sets\n",
5381 (Int)HG_(cardinalityWSU)( univ_laog ));
5382 }
5383
5384 //VG_(printf)("L(ast)L(ock) map: %'8lu inserts (%d map size)\n",
5385 // stats__ga_LL_adds,
5386 // (Int)(ga_to_lastlock ? VG_(sizeFM)( ga_to_lastlock ) : 0) );
5387
5388 VG_(printf)(" LockN-to-P map: %'8llu queries (%llu map size)\n",
5389 HG_(stats__LockN_to_P_queries),
5390 HG_(stats__LockN_to_P_get_map_size)() );
5391
philipped005b2c2015-04-21 21:58:14 +00005392 VG_(printf)("client malloc-ed blocks: %'8d\n",
5393 VG_(HT_count_nodes)(hg_mallocmeta_table));
5394
philippe8587b542013-12-15 20:24:43 +00005395 VG_(printf)("string table map: %'8llu queries (%llu map size)\n",
5396 HG_(stats__string_table_queries),
5397 HG_(stats__string_table_get_map_size)() );
5398 if (HG_(clo_track_lockorders)) {
5399 VG_(printf)(" LAOG: %'8d map size\n",
5400 (Int)(laog ? VG_(sizeFM)( laog ) : 0));
5401 VG_(printf)(" LAOG exposition: %'8d map size\n",
5402 (Int)(laog_exposition ? VG_(sizeFM)( laog_exposition ) : 0));
5403 }
5404
5405 VG_(printf)(" locks: %'8lu acquires, "
5406 "%'lu releases\n",
5407 stats__lockN_acquires,
5408 stats__lockN_releases
5409 );
5410 VG_(printf)(" sanity checks: %'8lu\n", stats__sanity_checks);
5411
5412 VG_(printf)("\n");
5413 libhb_shutdown(True); // This in fact only print stats.
5414}
5415
sewardjb4112022007-11-09 22:49:28 +00005416static void hg_fini ( Int exitcode )
5417{
sewardj2d9e8742009-08-07 15:46:56 +00005418 if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)) {
5419 VG_(message)(Vg_UserMsg,
5420 "For counts of detected and suppressed errors, "
5421 "rerun with: -v\n");
5422 }
5423
5424 if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)
5425 && HG_(clo_history_level) >= 2) {
5426 VG_(umsg)(
5427 "Use --history-level=approx or =none to gain increased speed, at\n" );
5428 VG_(umsg)(
5429 "the cost of reduced accuracy of conflicting-access information\n");
5430 }
5431
sewardjb4112022007-11-09 22:49:28 +00005432 if (SHOW_DATA_STRUCTURES)
5433 pp_everything( PP_ALL, "SK_(fini)" );
sewardjf98e1c02008-10-25 16:22:41 +00005434 if (HG_(clo_sanity_flags))
sewardjb4112022007-11-09 22:49:28 +00005435 all__sanity_check("SK_(fini)");
5436
philippe8587b542013-12-15 20:24:43 +00005437 if (VG_(clo_stats))
5438 hg_print_stats();
sewardjb4112022007-11-09 22:49:28 +00005439}
5440
sewardjf98e1c02008-10-25 16:22:41 +00005441/* FIXME: move these somewhere sane */
5442
5443static
5444void for_libhb__get_stacktrace ( Thr* hbt, Addr* frames, UWord nRequest )
5445{
5446 Thread* thr;
5447 ThreadId tid;
5448 UWord nActual;
5449 tl_assert(hbt);
sewardj60626642011-03-10 15:14:37 +00005450 thr = libhb_get_Thr_hgthread( hbt );
sewardjf98e1c02008-10-25 16:22:41 +00005451 tl_assert(thr);
5452 tid = map_threads_maybe_reverse_lookup_SLOW(thr);
5453 nActual = (UWord)VG_(get_StackTrace)( tid, frames, (UInt)nRequest,
5454 NULL, NULL, 0 );
5455 tl_assert(nActual <= nRequest);
5456 for (; nActual < nRequest; nActual++)
5457 frames[nActual] = 0;
5458}
5459
5460static
sewardj23f12002009-07-24 08:45:08 +00005461ExeContext* for_libhb__get_EC ( Thr* hbt )
sewardjf98e1c02008-10-25 16:22:41 +00005462{
5463 Thread* thr;
5464 ThreadId tid;
5465 ExeContext* ec;
5466 tl_assert(hbt);
sewardj60626642011-03-10 15:14:37 +00005467 thr = libhb_get_Thr_hgthread( hbt );
sewardjf98e1c02008-10-25 16:22:41 +00005468 tl_assert(thr);
5469 tid = map_threads_maybe_reverse_lookup_SLOW(thr);
sewardj23f12002009-07-24 08:45:08 +00005470 /* this will assert if tid is invalid */
sewardjf98e1c02008-10-25 16:22:41 +00005471 ec = VG_(record_ExeContext)( tid, 0 );
sewardjd52392d2008-11-08 20:36:26 +00005472 return ec;
sewardjf98e1c02008-10-25 16:22:41 +00005473}
5474
5475
sewardjc1fb9d22011-02-28 09:03:44 +00005476static void hg_post_clo_init ( void )
sewardjb4112022007-11-09 22:49:28 +00005477{
sewardjf98e1c02008-10-25 16:22:41 +00005478 Thr* hbthr_root;
njnf76d27a2009-05-28 01:53:07 +00005479
sewardjc1fb9d22011-02-28 09:03:44 +00005480 /////////////////////////////////////////////
5481 hbthr_root = libhb_init( for_libhb__get_stacktrace,
5482 for_libhb__get_EC );
5483 /////////////////////////////////////////////
5484
5485
5486 if (HG_(clo_track_lockorders))
5487 laog__init();
5488
5489 initialise_data_structures(hbthr_root);
5490}
5491
philippe07c08522014-05-14 20:39:27 +00005492static void hg_info_location (Addr a)
5493{
5494 (void) HG_(get_and_pp_addrdescr) (a);
5495}
5496
sewardjc1fb9d22011-02-28 09:03:44 +00005497static void hg_pre_clo_init ( void )
5498{
sewardjb4112022007-11-09 22:49:28 +00005499 VG_(details_name) ("Helgrind");
5500 VG_(details_version) (NULL);
5501 VG_(details_description) ("a thread error detector");
5502 VG_(details_copyright_author)(
sewardj0f157dd2013-10-18 14:27:36 +00005503 "Copyright (C) 2007-2013, and GNU GPL'd, by OpenWorks LLP et al.");
sewardjb4112022007-11-09 22:49:28 +00005504 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj9c08c0f2011-03-10 15:01:14 +00005505 VG_(details_avg_translation_sizeB) ( 320 );
sewardjb4112022007-11-09 22:49:28 +00005506
5507 VG_(basic_tool_funcs) (hg_post_clo_init,
5508 hg_instrument,
5509 hg_fini);
5510
5511 VG_(needs_core_errors) ();
sewardjf98e1c02008-10-25 16:22:41 +00005512 VG_(needs_tool_errors) (HG_(eq_Error),
sewardj24118492009-07-15 14:50:02 +00005513 HG_(before_pp_Error),
sewardjf98e1c02008-10-25 16:22:41 +00005514 HG_(pp_Error),
sewardjb4112022007-11-09 22:49:28 +00005515 False,/*show TIDs for errors*/
sewardjf98e1c02008-10-25 16:22:41 +00005516 HG_(update_extra),
5517 HG_(recognised_suppression),
5518 HG_(read_extra_suppression_info),
5519 HG_(error_matches_suppression),
5520 HG_(get_error_name),
philippe4e32d672013-10-17 22:10:41 +00005521 HG_(get_extra_suppression_info),
5522 HG_(print_extra_suppression_use),
5523 HG_(update_extra_suppression_use));
sewardjb4112022007-11-09 22:49:28 +00005524
sewardj24118492009-07-15 14:50:02 +00005525 VG_(needs_xml_output) ();
5526
sewardjb4112022007-11-09 22:49:28 +00005527 VG_(needs_command_line_options)(hg_process_cmd_line_option,
5528 hg_print_usage,
5529 hg_print_debug_usage);
5530 VG_(needs_client_requests) (hg_handle_client_request);
5531
5532 // FIXME?
5533 //VG_(needs_sanity_checks) (hg_cheap_sanity_check,
5534 // hg_expensive_sanity_check);
5535
philippe8587b542013-12-15 20:24:43 +00005536 VG_(needs_print_stats) (hg_print_stats);
philippe07c08522014-05-14 20:39:27 +00005537 VG_(needs_info_location) (hg_info_location);
philippe8587b542013-12-15 20:24:43 +00005538
sewardjb4112022007-11-09 22:49:28 +00005539 VG_(needs_malloc_replacement) (hg_cli__malloc,
5540 hg_cli____builtin_new,
5541 hg_cli____builtin_vec_new,
5542 hg_cli__memalign,
5543 hg_cli__calloc,
5544 hg_cli__free,
5545 hg_cli____builtin_delete,
5546 hg_cli____builtin_vec_delete,
5547 hg_cli__realloc,
njn8b140de2009-02-17 04:31:18 +00005548 hg_cli_malloc_usable_size,
philipped99c26a2012-07-31 22:17:28 +00005549 HG_CLI__DEFAULT_MALLOC_REDZONE_SZB );
sewardjb4112022007-11-09 22:49:28 +00005550
sewardj849b0ed2008-12-21 10:43:10 +00005551 /* 21 Dec 08: disabled this; it mostly causes H to start more
5552 slowly and use significantly more memory, without very often
5553 providing useful results. The user can request to load this
5554 information manually with --read-var-info=yes. */
5555 if (0) VG_(needs_var_info)(); /* optional */
sewardjb4112022007-11-09 22:49:28 +00005556
5557 VG_(track_new_mem_startup) ( evh__new_mem_w_perms );
sewardj7cf4e6b2008-05-01 20:24:26 +00005558 VG_(track_new_mem_stack_signal)( evh__new_mem_w_tid );
5559 VG_(track_new_mem_brk) ( evh__new_mem_w_tid );
sewardjb4112022007-11-09 22:49:28 +00005560 VG_(track_new_mem_mmap) ( evh__new_mem_w_perms );
sewardj1f77fec2010-04-12 19:51:04 +00005561 VG_(track_new_mem_stack) ( evh__new_mem_stack );
sewardjb4112022007-11-09 22:49:28 +00005562
5563 // FIXME: surely this isn't thread-aware
sewardj23f12002009-07-24 08:45:08 +00005564 VG_(track_copy_mem_remap) ( evh__copy_mem );
sewardjb4112022007-11-09 22:49:28 +00005565
5566 VG_(track_change_mem_mprotect) ( evh__set_perms );
5567
5568 VG_(track_die_mem_stack_signal)( evh__die_mem );
sewardjfd35d492011-03-17 19:39:55 +00005569 VG_(track_die_mem_brk) ( evh__die_mem_munmap );
5570 VG_(track_die_mem_munmap) ( evh__die_mem_munmap );
philippefc00a2a2015-05-15 11:41:54 +00005571
5572 /* evh__die_mem calls at the end libhb_srange_noaccess_NoFX
5573 which has no effect. We do not use VG_(track_die_mem_stack),
5574 as this would be an expensive way to do nothing. */
5575 // VG_(track_die_mem_stack) ( evh__die_mem );
sewardjb4112022007-11-09 22:49:28 +00005576
5577 // FIXME: what is this for?
5578 VG_(track_ban_mem_stack) (NULL);
5579
5580 VG_(track_pre_mem_read) ( evh__pre_mem_read );
5581 VG_(track_pre_mem_read_asciiz) ( evh__pre_mem_read_asciiz );
5582 VG_(track_pre_mem_write) ( evh__pre_mem_write );
5583 VG_(track_post_mem_write) (NULL);
5584
5585 /////////////////
5586
5587 VG_(track_pre_thread_ll_create)( evh__pre_thread_ll_create );
5588 VG_(track_pre_thread_ll_exit) ( evh__pre_thread_ll_exit );
5589
5590 VG_(track_start_client_code)( evh__start_client_code );
5591 VG_(track_stop_client_code)( evh__stop_client_code );
5592
sewardjb4112022007-11-09 22:49:28 +00005593 /* Ensure that requirements for "dodgy C-as-C++ style inheritance"
5594 as described in comments at the top of pub_tool_hashtable.h, are
5595 met. Blargh. */
5596 tl_assert( sizeof(void*) == sizeof(struct _MallocMeta*) );
5597 tl_assert( sizeof(UWord) == sizeof(Addr) );
5598 hg_mallocmeta_table
5599 = VG_(HT_construct)( "hg_malloc_metadata_table" );
5600
philippe5fbc9762013-12-01 19:28:48 +00005601 MallocMeta_poolalloc = VG_(newPA) ( sizeof(MallocMeta),
5602 1000,
5603 HG_(zalloc),
5604 "hg_malloc_metadata_pool",
5605 HG_(free));
5606
sewardj61bc2c52011-02-09 10:34:00 +00005607 // add a callback to clean up on (threaded) fork.
5608 VG_(atfork)(NULL/*pre*/, NULL/*parent*/, evh__atfork_child/*child*/);
sewardjb4112022007-11-09 22:49:28 +00005609}
5610
5611VG_DETERMINE_INTERFACE_VERSION(hg_pre_clo_init)
5612
5613/*--------------------------------------------------------------------*/
5614/*--- end hg_main.c ---*/
5615/*--------------------------------------------------------------------*/