blob: bbda2c033ea5c979aecd947a692c21cf12a77e45 [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
sewardj9eecbbb2010-05-03 21:37:12 +000011 Copyright (C) 2007-2010 OpenWorks LLP
sewardjb4112022007-11-09 22:49:28 +000012 info@open-works.co.uk
13
sewardj9eecbbb2010-05-03 21:37:12 +000014 Copyright (C) 2007-2010 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"
sewardjb4112022007-11-09 22:49:28 +000040#include "pub_tool_libcassert.h"
41#include "pub_tool_libcbase.h"
42#include "pub_tool_libcprint.h"
sewardjb4112022007-11-09 22:49:28 +000043#include "pub_tool_threadstate.h"
44#include "pub_tool_tooliface.h"
45#include "pub_tool_hashtable.h"
46#include "pub_tool_replacemalloc.h"
47#include "pub_tool_machine.h"
48#include "pub_tool_options.h"
49#include "pub_tool_xarray.h"
50#include "pub_tool_stacktrace.h"
sewardj896f6f92008-08-19 08:38:52 +000051#include "pub_tool_wordfm.h"
sewardja0eee322009-07-31 08:46:35 +000052#include "pub_tool_debuginfo.h" // VG_(find_seginfo), VG_(seginfo_soname)
53#include "pub_tool_redir.h" // sonames for the dynamic linkers
54#include "pub_tool_vki.h" // VKI_PAGE_SIZE
sewardj61bc2c52011-02-09 10:34:00 +000055#include "pub_tool_libcproc.h" // VG_(atfork)
sewardj234e5582011-02-09 12:47:23 +000056#include "pub_tool_aspacemgr.h" // VG_(am_is_valid_for_client)
sewardjb4112022007-11-09 22:49:28 +000057
sewardjf98e1c02008-10-25 16:22:41 +000058#include "hg_basics.h"
59#include "hg_wordset.h"
60#include "hg_lock_n_thread.h"
61#include "hg_errors.h"
62
63#include "libhb.h"
64
sewardjb4112022007-11-09 22:49:28 +000065#include "helgrind.h"
66
sewardjf98e1c02008-10-25 16:22:41 +000067
68// FIXME: new_mem_w_tid ignores the supplied tid. (wtf?!)
69
70// FIXME: when client destroys a lock or a CV, remove these
71// from our mappings, so that the associated SO can be freed up
sewardjb4112022007-11-09 22:49:28 +000072
73/*----------------------------------------------------------------*/
74/*--- ---*/
75/*----------------------------------------------------------------*/
76
sewardj11e352f2007-11-30 11:11:02 +000077/* Note this needs to be compiled with -fno-strict-aliasing, since it
78 contains a whole bunch of calls to lookupFM etc which cast between
79 Word and pointer types. gcc rightly complains this breaks ANSI C
80 strict aliasing rules, at -O2. No complaints at -O, but -O2 gives
81 worthwhile performance benefits over -O.
sewardjc17be792007-11-10 22:50:13 +000082*/
sewardjb4112022007-11-09 22:49:28 +000083
84// FIXME what is supposed to happen to locks in memory which
85// is relocated as a result of client realloc?
86
sewardjb4112022007-11-09 22:49:28 +000087// FIXME put referencing ThreadId into Thread and get
88// rid of the slow reverse mapping function.
89
90// FIXME accesses to NoAccess areas: change state to Excl?
91
92// FIXME report errors for accesses of NoAccess memory?
93
94// FIXME pth_cond_wait/timedwait wrappers. Even if these fail,
95// the thread still holds the lock.
96
97/* ------------ Debug/trace options ------------ */
98
sewardjb4112022007-11-09 22:49:28 +000099// 0 for silent, 1 for some stuff, 2 for lots of stuff
100#define SHOW_EVENTS 0
101
sewardjb4112022007-11-09 22:49:28 +0000102
103static void all__sanity_check ( Char* who ); /* fwds */
104
105#define HG_CLI__MALLOC_REDZONE_SZB 16 /* let's say */
106
107// 0 for none, 1 for dump at end of run
108#define SHOW_DATA_STRUCTURES 0
109
110
sewardjb4112022007-11-09 22:49:28 +0000111/* ------------ Misc comments ------------ */
112
113// FIXME: don't hardwire initial entries for root thread.
114// Instead, let the pre_thread_ll_create handler do this.
115
sewardjb4112022007-11-09 22:49:28 +0000116
117/*----------------------------------------------------------------*/
sewardjf98e1c02008-10-25 16:22:41 +0000118/*--- Primary data structures ---*/
sewardjb4112022007-11-09 22:49:28 +0000119/*----------------------------------------------------------------*/
120
sewardjb4112022007-11-09 22:49:28 +0000121/* Admin linked list of Threads */
122static Thread* admin_threads = NULL;
123
sewardj1d7c3322011-02-28 09:22:51 +0000124/* Admin double linked list of Locks */
125/* We need a double linked list to properly and efficiently
126 handle del_LockN. */
sewardjb4112022007-11-09 22:49:28 +0000127static Lock* admin_locks = NULL;
128
sewardjb4112022007-11-09 22:49:28 +0000129/* Mapping table for core ThreadIds to Thread* */
130static Thread** map_threads = NULL; /* Array[VG_N_THREADS] of Thread* */
131
sewardjb4112022007-11-09 22:49:28 +0000132/* Mapping table for lock guest addresses to Lock* */
133static WordFM* map_locks = NULL; /* WordFM LockAddr Lock* */
134
sewardj0f64c9e2011-03-10 17:40:22 +0000135/* The word-set universes for lock sets. */
sewardjb4112022007-11-09 22:49:28 +0000136static WordSetU* univ_lsets = NULL; /* sets of Lock* */
137static WordSetU* univ_laog = NULL; /* sets of Lock*, for LAOG */
138
sewardjb4112022007-11-09 22:49:28 +0000139
140/*----------------------------------------------------------------*/
141/*--- Simple helpers for the data structures ---*/
142/*----------------------------------------------------------------*/
143
144static UWord stats__lockN_acquires = 0;
145static UWord stats__lockN_releases = 0;
146
sewardjf98e1c02008-10-25 16:22:41 +0000147static
148ThreadId map_threads_maybe_reverse_lookup_SLOW ( Thread* thr ); /*fwds*/
sewardjb4112022007-11-09 22:49:28 +0000149
150/* --------- Constructors --------- */
151
sewardjf98e1c02008-10-25 16:22:41 +0000152static Thread* mk_Thread ( Thr* hbthr ) {
sewardjb4112022007-11-09 22:49:28 +0000153 static Int indx = 1;
sewardjf98e1c02008-10-25 16:22:41 +0000154 Thread* thread = HG_(zalloc)( "hg.mk_Thread.1", sizeof(Thread) );
sewardjb4112022007-11-09 22:49:28 +0000155 thread->locksetA = HG_(emptyWS)( univ_lsets );
156 thread->locksetW = HG_(emptyWS)( univ_lsets );
sewardjb4112022007-11-09 22:49:28 +0000157 thread->magic = Thread_MAGIC;
sewardjf98e1c02008-10-25 16:22:41 +0000158 thread->hbthr = hbthr;
159 thread->coretid = VG_INVALID_THREADID;
sewardjb4112022007-11-09 22:49:28 +0000160 thread->created_at = NULL;
161 thread->announced = False;
162 thread->errmsg_index = indx++;
163 thread->admin = admin_threads;
164 admin_threads = thread;
165 return thread;
166}
sewardjf98e1c02008-10-25 16:22:41 +0000167
sewardjb4112022007-11-09 22:49:28 +0000168// Make a new lock which is unlocked (hence ownerless)
sewardj1d7c3322011-02-28 09:22:51 +0000169// and insert the new lock in admin_locks double linked list.
sewardjb4112022007-11-09 22:49:28 +0000170static Lock* mk_LockN ( LockKind kind, Addr guestaddr ) {
171 static ULong unique = 0;
sewardjf98e1c02008-10-25 16:22:41 +0000172 Lock* lock = HG_(zalloc)( "hg.mk_Lock.1", sizeof(Lock) );
sewardj0f64c9e2011-03-10 17:40:22 +0000173 /* begin: add to double linked list */
sewardj1d7c3322011-02-28 09:22:51 +0000174 if (admin_locks)
175 admin_locks->admin_prev = lock;
sewardj0f64c9e2011-03-10 17:40:22 +0000176 lock->admin_next = admin_locks;
177 lock->admin_prev = NULL;
sewardj1d7c3322011-02-28 09:22:51 +0000178 admin_locks = lock;
sewardj0f64c9e2011-03-10 17:40:22 +0000179 /* end: add */
sewardjb4112022007-11-09 22:49:28 +0000180 lock->unique = unique++;
181 lock->magic = LockN_MAGIC;
182 lock->appeared_at = NULL;
183 lock->acquired_at = NULL;
sewardjf98e1c02008-10-25 16:22:41 +0000184 lock->hbso = libhb_so_alloc();
sewardjb4112022007-11-09 22:49:28 +0000185 lock->guestaddr = guestaddr;
186 lock->kind = kind;
187 lock->heldW = False;
188 lock->heldBy = NULL;
sewardjf98e1c02008-10-25 16:22:41 +0000189 tl_assert(HG_(is_sane_LockN)(lock));
sewardjb4112022007-11-09 22:49:28 +0000190 return lock;
191}
sewardjb4112022007-11-09 22:49:28 +0000192
193/* Release storage for a Lock. Also release storage in .heldBy, if
sewardj1d7c3322011-02-28 09:22:51 +0000194 any. Removes from admin_locks double linked list. */
sewardjb4112022007-11-09 22:49:28 +0000195static void del_LockN ( Lock* lk )
196{
sewardjf98e1c02008-10-25 16:22:41 +0000197 tl_assert(HG_(is_sane_LockN)(lk));
198 tl_assert(lk->hbso);
199 libhb_so_dealloc(lk->hbso);
sewardjb4112022007-11-09 22:49:28 +0000200 if (lk->heldBy)
sewardj896f6f92008-08-19 08:38:52 +0000201 VG_(deleteBag)( lk->heldBy );
sewardj0f64c9e2011-03-10 17:40:22 +0000202 /* begin: del lock from double linked list */
203 if (lk == admin_locks) {
204 tl_assert(lk->admin_prev == NULL);
205 if (lk->admin_next)
206 lk->admin_next->admin_prev = NULL;
sewardj1d7c3322011-02-28 09:22:51 +0000207 admin_locks = lk->admin_next;
sewardj1d7c3322011-02-28 09:22:51 +0000208 }
209 else {
sewardj0f64c9e2011-03-10 17:40:22 +0000210 tl_assert(lk->admin_prev != NULL);
sewardj1d7c3322011-02-28 09:22:51 +0000211 lk->admin_prev->admin_next = lk->admin_next;
sewardj0f64c9e2011-03-10 17:40:22 +0000212 if (lk->admin_next)
213 lk->admin_next->admin_prev = lk->admin_prev;
sewardj1d7c3322011-02-28 09:22:51 +0000214 }
sewardj0f64c9e2011-03-10 17:40:22 +0000215 /* end: del */
sewardjb4112022007-11-09 22:49:28 +0000216 VG_(memset)(lk, 0xAA, sizeof(*lk));
sewardjf98e1c02008-10-25 16:22:41 +0000217 HG_(free)(lk);
sewardjb4112022007-11-09 22:49:28 +0000218}
219
220/* Update 'lk' to reflect that 'thr' now has a write-acquisition of
221 it. This is done strictly: only combinations resulting from
222 correct program and libpthread behaviour are allowed. */
223static void lockN_acquire_writer ( Lock* lk, Thread* thr )
224{
sewardjf98e1c02008-10-25 16:22:41 +0000225 tl_assert(HG_(is_sane_LockN)(lk));
226 tl_assert(HG_(is_sane_Thread)(thr));
sewardjb4112022007-11-09 22:49:28 +0000227
228 stats__lockN_acquires++;
229
230 /* EXPOSITION only */
231 /* We need to keep recording snapshots of where the lock was
232 acquired, so as to produce better lock-order error messages. */
233 if (lk->acquired_at == NULL) {
234 ThreadId tid;
235 tl_assert(lk->heldBy == NULL);
236 tid = map_threads_maybe_reverse_lookup_SLOW(thr);
237 lk->acquired_at
sewardjf98e1c02008-10-25 16:22:41 +0000238 = VG_(record_ExeContext)(tid, 0/*first_ip_delta*/);
sewardjb4112022007-11-09 22:49:28 +0000239 } else {
240 tl_assert(lk->heldBy != NULL);
241 }
242 /* end EXPOSITION only */
243
244 switch (lk->kind) {
245 case LK_nonRec:
246 case_LK_nonRec:
247 tl_assert(lk->heldBy == NULL); /* can't w-lock recursively */
248 tl_assert(!lk->heldW);
249 lk->heldW = True;
sewardjf98e1c02008-10-25 16:22:41 +0000250 lk->heldBy = VG_(newBag)( HG_(zalloc), "hg.lNaw.1", HG_(free) );
sewardj896f6f92008-08-19 08:38:52 +0000251 VG_(addToBag)( lk->heldBy, (Word)thr );
sewardjb4112022007-11-09 22:49:28 +0000252 break;
253 case LK_mbRec:
254 if (lk->heldBy == NULL)
255 goto case_LK_nonRec;
256 /* 2nd and subsequent locking of a lock by its owner */
257 tl_assert(lk->heldW);
258 /* assert: lk is only held by one thread .. */
sewardj896f6f92008-08-19 08:38:52 +0000259 tl_assert(VG_(sizeUniqueBag(lk->heldBy)) == 1);
sewardjb4112022007-11-09 22:49:28 +0000260 /* assert: .. and that thread is 'thr'. */
sewardj896f6f92008-08-19 08:38:52 +0000261 tl_assert(VG_(elemBag)(lk->heldBy, (Word)thr)
262 == VG_(sizeTotalBag)(lk->heldBy));
263 VG_(addToBag)(lk->heldBy, (Word)thr);
sewardjb4112022007-11-09 22:49:28 +0000264 break;
265 case LK_rdwr:
266 tl_assert(lk->heldBy == NULL && !lk->heldW); /* must be unheld */
267 goto case_LK_nonRec;
268 default:
269 tl_assert(0);
270 }
sewardjf98e1c02008-10-25 16:22:41 +0000271 tl_assert(HG_(is_sane_LockN)(lk));
sewardjb4112022007-11-09 22:49:28 +0000272}
273
274static void lockN_acquire_reader ( Lock* lk, Thread* thr )
275{
sewardjf98e1c02008-10-25 16:22:41 +0000276 tl_assert(HG_(is_sane_LockN)(lk));
277 tl_assert(HG_(is_sane_Thread)(thr));
sewardjb4112022007-11-09 22:49:28 +0000278 /* can only add reader to a reader-writer lock. */
279 tl_assert(lk->kind == LK_rdwr);
280 /* lk must be free or already r-held. */
281 tl_assert(lk->heldBy == NULL
282 || (lk->heldBy != NULL && !lk->heldW));
283
284 stats__lockN_acquires++;
285
286 /* EXPOSITION only */
287 /* We need to keep recording snapshots of where the lock was
288 acquired, so as to produce better lock-order error messages. */
289 if (lk->acquired_at == NULL) {
290 ThreadId tid;
291 tl_assert(lk->heldBy == NULL);
292 tid = map_threads_maybe_reverse_lookup_SLOW(thr);
293 lk->acquired_at
sewardjf98e1c02008-10-25 16:22:41 +0000294 = VG_(record_ExeContext)(tid, 0/*first_ip_delta*/);
sewardjb4112022007-11-09 22:49:28 +0000295 } else {
296 tl_assert(lk->heldBy != NULL);
297 }
298 /* end EXPOSITION only */
299
300 if (lk->heldBy) {
sewardj896f6f92008-08-19 08:38:52 +0000301 VG_(addToBag)(lk->heldBy, (Word)thr);
sewardjb4112022007-11-09 22:49:28 +0000302 } else {
303 lk->heldW = False;
sewardjf98e1c02008-10-25 16:22:41 +0000304 lk->heldBy = VG_(newBag)( HG_(zalloc), "hg.lNar.1", HG_(free) );
sewardj896f6f92008-08-19 08:38:52 +0000305 VG_(addToBag)( lk->heldBy, (Word)thr );
sewardjb4112022007-11-09 22:49:28 +0000306 }
307 tl_assert(!lk->heldW);
sewardjf98e1c02008-10-25 16:22:41 +0000308 tl_assert(HG_(is_sane_LockN)(lk));
sewardjb4112022007-11-09 22:49:28 +0000309}
310
311/* Update 'lk' to reflect a release of it by 'thr'. This is done
312 strictly: only combinations resulting from correct program and
313 libpthread behaviour are allowed. */
314
315static void lockN_release ( Lock* lk, Thread* thr )
316{
317 Bool b;
sewardjf98e1c02008-10-25 16:22:41 +0000318 tl_assert(HG_(is_sane_LockN)(lk));
319 tl_assert(HG_(is_sane_Thread)(thr));
sewardjb4112022007-11-09 22:49:28 +0000320 /* lock must be held by someone */
321 tl_assert(lk->heldBy);
322 stats__lockN_releases++;
323 /* Remove it from the holder set */
sewardj896f6f92008-08-19 08:38:52 +0000324 b = VG_(delFromBag)(lk->heldBy, (Word)thr);
sewardjb4112022007-11-09 22:49:28 +0000325 /* thr must actually have been a holder of lk */
326 tl_assert(b);
327 /* normalise */
328 tl_assert(lk->acquired_at);
sewardj896f6f92008-08-19 08:38:52 +0000329 if (VG_(isEmptyBag)(lk->heldBy)) {
330 VG_(deleteBag)(lk->heldBy);
sewardjb4112022007-11-09 22:49:28 +0000331 lk->heldBy = NULL;
332 lk->heldW = False;
333 lk->acquired_at = NULL;
334 }
sewardjf98e1c02008-10-25 16:22:41 +0000335 tl_assert(HG_(is_sane_LockN)(lk));
sewardjb4112022007-11-09 22:49:28 +0000336}
337
338static void remove_Lock_from_locksets_of_all_owning_Threads( Lock* lk )
339{
340 Thread* thr;
341 if (!lk->heldBy) {
342 tl_assert(!lk->heldW);
343 return;
344 }
345 /* for each thread that holds this lock do ... */
sewardj896f6f92008-08-19 08:38:52 +0000346 VG_(initIterBag)( lk->heldBy );
347 while (VG_(nextIterBag)( lk->heldBy, (Word*)&thr, NULL )) {
sewardjf98e1c02008-10-25 16:22:41 +0000348 tl_assert(HG_(is_sane_Thread)(thr));
sewardjb4112022007-11-09 22:49:28 +0000349 tl_assert(HG_(elemWS)( univ_lsets,
350 thr->locksetA, (Word)lk ));
351 thr->locksetA
352 = HG_(delFromWS)( univ_lsets, thr->locksetA, (Word)lk );
353
354 if (lk->heldW) {
355 tl_assert(HG_(elemWS)( univ_lsets,
356 thr->locksetW, (Word)lk ));
357 thr->locksetW
358 = HG_(delFromWS)( univ_lsets, thr->locksetW, (Word)lk );
359 }
360 }
sewardj896f6f92008-08-19 08:38:52 +0000361 VG_(doneIterBag)( lk->heldBy );
sewardjb4112022007-11-09 22:49:28 +0000362}
363
sewardjb4112022007-11-09 22:49:28 +0000364
365/*----------------------------------------------------------------*/
366/*--- Print out the primary data structures ---*/
367/*----------------------------------------------------------------*/
368
sewardjb4112022007-11-09 22:49:28 +0000369#define PP_THREADS (1<<1)
370#define PP_LOCKS (1<<2)
sewardjf98e1c02008-10-25 16:22:41 +0000371#define PP_ALL (PP_THREADS | PP_LOCKS)
sewardjb4112022007-11-09 22:49:28 +0000372
373
374static const Int sHOW_ADMIN = 0;
375
376static void space ( Int n )
377{
378 Int i;
379 Char spaces[128+1];
380 tl_assert(n >= 0 && n < 128);
381 if (n == 0)
382 return;
383 for (i = 0; i < n; i++)
384 spaces[i] = ' ';
385 spaces[i] = 0;
386 tl_assert(i < 128+1);
387 VG_(printf)("%s", spaces);
388}
389
390static void pp_Thread ( Int d, Thread* t )
391{
392 space(d+0); VG_(printf)("Thread %p {\n", t);
393 if (sHOW_ADMIN) {
394 space(d+3); VG_(printf)("admin %p\n", t->admin);
395 space(d+3); VG_(printf)("magic 0x%x\n", (UInt)t->magic);
396 }
397 space(d+3); VG_(printf)("locksetA %d\n", (Int)t->locksetA);
398 space(d+3); VG_(printf)("locksetW %d\n", (Int)t->locksetW);
sewardjb4112022007-11-09 22:49:28 +0000399 space(d+0); VG_(printf)("}\n");
400}
401
402static void pp_admin_threads ( Int d )
403{
404 Int i, n;
405 Thread* t;
406 for (n = 0, t = admin_threads; t; n++, t = t->admin) {
407 /* nothing */
408 }
409 space(d); VG_(printf)("admin_threads (%d records) {\n", n);
410 for (i = 0, t = admin_threads; t; i++, t = t->admin) {
411 if (0) {
412 space(n);
413 VG_(printf)("admin_threads record %d of %d:\n", i, n);
414 }
415 pp_Thread(d+3, t);
416 }
barta0b6b2c2008-07-07 06:49:24 +0000417 space(d); VG_(printf)("}\n");
sewardjb4112022007-11-09 22:49:28 +0000418}
419
420static void pp_map_threads ( Int d )
421{
njn4c245e52009-03-15 23:25:38 +0000422 Int i, n = 0;
sewardjb4112022007-11-09 22:49:28 +0000423 space(d); VG_(printf)("map_threads ");
sewardjb4112022007-11-09 22:49:28 +0000424 for (i = 0; i < VG_N_THREADS; i++) {
425 if (map_threads[i] != NULL)
426 n++;
427 }
428 VG_(printf)("(%d entries) {\n", n);
429 for (i = 0; i < VG_N_THREADS; i++) {
430 if (map_threads[i] == NULL)
431 continue;
432 space(d+3);
433 VG_(printf)("coretid %d -> Thread %p\n", i, map_threads[i]);
434 }
435 space(d); VG_(printf)("}\n");
436}
437
438static const HChar* show_LockKind ( LockKind lkk ) {
439 switch (lkk) {
440 case LK_mbRec: return "mbRec";
441 case LK_nonRec: return "nonRec";
442 case LK_rdwr: return "rdwr";
443 default: tl_assert(0);
444 }
445}
446
447static void pp_Lock ( Int d, Lock* lk )
448{
barta0b6b2c2008-07-07 06:49:24 +0000449 space(d+0); VG_(printf)("Lock %p (ga %#lx) {\n", lk, lk->guestaddr);
sewardjb4112022007-11-09 22:49:28 +0000450 if (sHOW_ADMIN) {
sewardj1d7c3322011-02-28 09:22:51 +0000451 space(d+3); VG_(printf)("admin_n %p\n", lk->admin_next);
452 space(d+3); VG_(printf)("admin_p %p\n", lk->admin_prev);
453 space(d+3); VG_(printf)("magic 0x%x\n", (UInt)lk->magic);
sewardjb4112022007-11-09 22:49:28 +0000454 }
455 space(d+3); VG_(printf)("unique %llu\n", lk->unique);
456 space(d+3); VG_(printf)("kind %s\n", show_LockKind(lk->kind));
457 space(d+3); VG_(printf)("heldW %s\n", lk->heldW ? "yes" : "no");
458 space(d+3); VG_(printf)("heldBy %p", lk->heldBy);
459 if (lk->heldBy) {
460 Thread* thr;
461 Word count;
462 VG_(printf)(" { ");
sewardj896f6f92008-08-19 08:38:52 +0000463 VG_(initIterBag)( lk->heldBy );
464 while (VG_(nextIterBag)( lk->heldBy, (Word*)&thr, &count ))
sewardjb4112022007-11-09 22:49:28 +0000465 VG_(printf)("%lu:%p ", count, thr);
sewardj896f6f92008-08-19 08:38:52 +0000466 VG_(doneIterBag)( lk->heldBy );
sewardjb4112022007-11-09 22:49:28 +0000467 VG_(printf)("}");
468 }
469 VG_(printf)("\n");
470 space(d+0); VG_(printf)("}\n");
471}
472
473static void pp_admin_locks ( Int d )
474{
475 Int i, n;
476 Lock* lk;
sewardj1d7c3322011-02-28 09:22:51 +0000477 for (n = 0, lk = admin_locks; lk; n++, lk = lk->admin_next) {
sewardjb4112022007-11-09 22:49:28 +0000478 /* nothing */
479 }
480 space(d); VG_(printf)("admin_locks (%d records) {\n", n);
sewardj1d7c3322011-02-28 09:22:51 +0000481 for (i = 0, lk = admin_locks; lk; i++, lk = lk->admin_next) {
sewardjb4112022007-11-09 22:49:28 +0000482 if (0) {
483 space(n);
484 VG_(printf)("admin_locks record %d of %d:\n", i, n);
485 }
486 pp_Lock(d+3, lk);
487 }
barta0b6b2c2008-07-07 06:49:24 +0000488 space(d); VG_(printf)("}\n");
sewardjb4112022007-11-09 22:49:28 +0000489}
490
491static void pp_map_locks ( Int d )
492{
493 void* gla;
494 Lock* lk;
495 space(d); VG_(printf)("map_locks (%d entries) {\n",
sewardj896f6f92008-08-19 08:38:52 +0000496 (Int)VG_(sizeFM)( map_locks ));
497 VG_(initIterFM)( map_locks );
498 while (VG_(nextIterFM)( map_locks, (Word*)&gla,
sewardjb5f29642007-11-16 12:02:43 +0000499 (Word*)&lk )) {
sewardjb4112022007-11-09 22:49:28 +0000500 space(d+3);
501 VG_(printf)("guest %p -> Lock %p\n", gla, lk);
502 }
sewardj896f6f92008-08-19 08:38:52 +0000503 VG_(doneIterFM)( map_locks );
sewardjb4112022007-11-09 22:49:28 +0000504 space(d); VG_(printf)("}\n");
505}
506
sewardjb4112022007-11-09 22:49:28 +0000507static void pp_everything ( Int flags, Char* caller )
508{
509 Int d = 0;
510 VG_(printf)("\n");
511 VG_(printf)("All_Data_Structures (caller = \"%s\") {\n", caller);
512 if (flags & PP_THREADS) {
513 VG_(printf)("\n");
514 pp_admin_threads(d+3);
515 VG_(printf)("\n");
516 pp_map_threads(d+3);
517 }
518 if (flags & PP_LOCKS) {
519 VG_(printf)("\n");
520 pp_admin_locks(d+3);
521 VG_(printf)("\n");
522 pp_map_locks(d+3);
523 }
sewardjb4112022007-11-09 22:49:28 +0000524
525 VG_(printf)("\n");
526 VG_(printf)("}\n");
527 VG_(printf)("\n");
528}
529
530#undef SHOW_ADMIN
531
532
533/*----------------------------------------------------------------*/
534/*--- Initialise the primary data structures ---*/
535/*----------------------------------------------------------------*/
536
sewardjf98e1c02008-10-25 16:22:41 +0000537static void initialise_data_structures ( Thr* hbthr_root )
sewardjb4112022007-11-09 22:49:28 +0000538{
sewardjb4112022007-11-09 22:49:28 +0000539 Thread* thr;
540
541 /* Get everything initialised and zeroed. */
542 tl_assert(admin_threads == NULL);
543 tl_assert(admin_locks == NULL);
sewardjb4112022007-11-09 22:49:28 +0000544
545 tl_assert(sizeof(Addr) == sizeof(Word));
sewardjb4112022007-11-09 22:49:28 +0000546
547 tl_assert(map_threads == NULL);
sewardjf98e1c02008-10-25 16:22:41 +0000548 map_threads = HG_(zalloc)( "hg.ids.1", VG_N_THREADS * sizeof(Thread*) );
sewardjb4112022007-11-09 22:49:28 +0000549 tl_assert(map_threads != NULL);
550
sewardjb4112022007-11-09 22:49:28 +0000551 tl_assert(sizeof(Addr) == sizeof(Word));
552 tl_assert(map_locks == NULL);
sewardjf98e1c02008-10-25 16:22:41 +0000553 map_locks = VG_(newFM)( HG_(zalloc), "hg.ids.2", HG_(free),
554 NULL/*unboxed Word cmp*/);
sewardjb4112022007-11-09 22:49:28 +0000555 tl_assert(map_locks != NULL);
556
sewardjb4112022007-11-09 22:49:28 +0000557 tl_assert(univ_lsets == NULL);
sewardjf98e1c02008-10-25 16:22:41 +0000558 univ_lsets = HG_(newWordSetU)( HG_(zalloc), "hg.ids.4", HG_(free),
559 8/*cacheSize*/ );
sewardjb4112022007-11-09 22:49:28 +0000560 tl_assert(univ_lsets != NULL);
561
562 tl_assert(univ_laog == NULL);
sewardjc1fb9d22011-02-28 09:03:44 +0000563 if (HG_(clo_track_lockorders)) {
564 univ_laog = HG_(newWordSetU)( HG_(zalloc), "hg.ids.5 (univ_laog)",
565 HG_(free), 24/*cacheSize*/ );
566 tl_assert(univ_laog != NULL);
567 }
sewardjb4112022007-11-09 22:49:28 +0000568
569 /* Set up entries for the root thread */
570 // FIXME: this assumes that the first real ThreadId is 1
571
sewardjb4112022007-11-09 22:49:28 +0000572 /* a Thread for the new thread ... */
sewardjf98e1c02008-10-25 16:22:41 +0000573 thr = mk_Thread(hbthr_root);
574 thr->coretid = 1; /* FIXME: hardwires an assumption about the
575 identity of the root thread. */
sewardj60626642011-03-10 15:14:37 +0000576 tl_assert( libhb_get_Thr_hgthread(hbthr_root) == NULL );
577 libhb_set_Thr_hgthread(hbthr_root, thr);
sewardjb4112022007-11-09 22:49:28 +0000578
sewardjf98e1c02008-10-25 16:22:41 +0000579 /* and bind it in the thread-map table. */
580 tl_assert(HG_(is_sane_ThreadId)(thr->coretid));
581 tl_assert(thr->coretid != VG_INVALID_THREADID);
sewardjb4112022007-11-09 22:49:28 +0000582
sewardjf98e1c02008-10-25 16:22:41 +0000583 map_threads[thr->coretid] = thr;
sewardjb4112022007-11-09 22:49:28 +0000584
585 tl_assert(VG_INVALID_THREADID == 0);
586
sewardjb4112022007-11-09 22:49:28 +0000587 all__sanity_check("initialise_data_structures");
588}
589
590
591/*----------------------------------------------------------------*/
sewardjf98e1c02008-10-25 16:22:41 +0000592/*--- map_threads :: array[core-ThreadId] of Thread* ---*/
sewardjb4112022007-11-09 22:49:28 +0000593/*----------------------------------------------------------------*/
594
595/* Doesn't assert if the relevant map_threads entry is NULL. */
596static Thread* map_threads_maybe_lookup ( ThreadId coretid )
597{
598 Thread* thr;
sewardjf98e1c02008-10-25 16:22:41 +0000599 tl_assert( HG_(is_sane_ThreadId)(coretid) );
sewardjb4112022007-11-09 22:49:28 +0000600 thr = map_threads[coretid];
601 return thr;
602}
603
604/* Asserts if the relevant map_threads entry is NULL. */
605static inline Thread* map_threads_lookup ( ThreadId coretid )
606{
607 Thread* thr;
sewardjf98e1c02008-10-25 16:22:41 +0000608 tl_assert( HG_(is_sane_ThreadId)(coretid) );
sewardjb4112022007-11-09 22:49:28 +0000609 thr = map_threads[coretid];
610 tl_assert(thr);
611 return thr;
612}
613
sewardjf98e1c02008-10-25 16:22:41 +0000614/* Do a reverse lookup. Does not assert if 'thr' is not found in
615 map_threads. */
sewardjb4112022007-11-09 22:49:28 +0000616static ThreadId map_threads_maybe_reverse_lookup_SLOW ( Thread* thr )
617{
sewardjf98e1c02008-10-25 16:22:41 +0000618 ThreadId tid;
619 tl_assert(HG_(is_sane_Thread)(thr));
sewardjb4112022007-11-09 22:49:28 +0000620 /* Check nobody used the invalid-threadid slot */
621 tl_assert(VG_INVALID_THREADID >= 0 && VG_INVALID_THREADID < VG_N_THREADS);
622 tl_assert(map_threads[VG_INVALID_THREADID] == NULL);
sewardjf98e1c02008-10-25 16:22:41 +0000623 tid = thr->coretid;
624 tl_assert(HG_(is_sane_ThreadId)(tid));
625 return tid;
sewardjb4112022007-11-09 22:49:28 +0000626}
627
628/* Do a reverse lookup. Warning: POTENTIALLY SLOW. Asserts if 'thr'
629 is not found in map_threads. */
630static ThreadId map_threads_reverse_lookup_SLOW ( Thread* thr )
631{
632 ThreadId tid = map_threads_maybe_reverse_lookup_SLOW( thr );
633 tl_assert(tid != VG_INVALID_THREADID);
sewardjf98e1c02008-10-25 16:22:41 +0000634 tl_assert(map_threads[tid]);
635 tl_assert(map_threads[tid]->coretid == tid);
sewardjb4112022007-11-09 22:49:28 +0000636 return tid;
637}
638
639static void map_threads_delete ( ThreadId coretid )
640{
641 Thread* thr;
642 tl_assert(coretid != 0);
sewardjf98e1c02008-10-25 16:22:41 +0000643 tl_assert( HG_(is_sane_ThreadId)(coretid) );
sewardjb4112022007-11-09 22:49:28 +0000644 thr = map_threads[coretid];
645 tl_assert(thr);
646 map_threads[coretid] = NULL;
647}
648
649
650/*----------------------------------------------------------------*/
651/*--- map_locks :: WordFM guest-Addr-of-lock Lock* ---*/
652/*----------------------------------------------------------------*/
653
654/* Make sure there is a lock table entry for the given (lock) guest
655 address. If not, create one of the stated 'kind' in unheld state.
656 In any case, return the address of the existing or new Lock. */
657static
658Lock* map_locks_lookup_or_create ( LockKind lkk, Addr ga, ThreadId tid )
659{
660 Bool found;
661 Lock* oldlock = NULL;
sewardjf98e1c02008-10-25 16:22:41 +0000662 tl_assert(HG_(is_sane_ThreadId)(tid));
sewardj896f6f92008-08-19 08:38:52 +0000663 found = VG_(lookupFM)( map_locks,
sewardjb5f29642007-11-16 12:02:43 +0000664 NULL, (Word*)&oldlock, (Word)ga );
sewardjb4112022007-11-09 22:49:28 +0000665 if (!found) {
666 Lock* lock = mk_LockN(lkk, ga);
667 lock->appeared_at = VG_(record_ExeContext)( tid, 0 );
sewardjf98e1c02008-10-25 16:22:41 +0000668 tl_assert(HG_(is_sane_LockN)(lock));
sewardj896f6f92008-08-19 08:38:52 +0000669 VG_(addToFM)( map_locks, (Word)ga, (Word)lock );
sewardjb4112022007-11-09 22:49:28 +0000670 tl_assert(oldlock == NULL);
sewardjb4112022007-11-09 22:49:28 +0000671 return lock;
672 } else {
673 tl_assert(oldlock != NULL);
sewardjf98e1c02008-10-25 16:22:41 +0000674 tl_assert(HG_(is_sane_LockN)(oldlock));
sewardjb4112022007-11-09 22:49:28 +0000675 tl_assert(oldlock->guestaddr == ga);
sewardjb4112022007-11-09 22:49:28 +0000676 return oldlock;
677 }
678}
679
680static Lock* map_locks_maybe_lookup ( Addr ga )
681{
682 Bool found;
683 Lock* lk = NULL;
sewardj896f6f92008-08-19 08:38:52 +0000684 found = VG_(lookupFM)( map_locks, NULL, (Word*)&lk, (Word)ga );
sewardjb4112022007-11-09 22:49:28 +0000685 tl_assert(found ? lk != NULL : lk == NULL);
sewardjb4112022007-11-09 22:49:28 +0000686 return lk;
687}
688
689static void map_locks_delete ( Addr ga )
690{
691 Addr ga2 = 0;
692 Lock* lk = NULL;
sewardj896f6f92008-08-19 08:38:52 +0000693 VG_(delFromFM)( map_locks,
sewardjb5f29642007-11-16 12:02:43 +0000694 (Word*)&ga2, (Word*)&lk, (Word)ga );
sewardjb4112022007-11-09 22:49:28 +0000695 /* delFromFM produces the val which is being deleted, if it is
696 found. So assert it is non-null; that in effect asserts that we
697 are deleting a (ga, Lock) pair which actually exists. */
698 tl_assert(lk != NULL);
699 tl_assert(ga2 == ga);
700}
701
702
sewardjb4112022007-11-09 22:49:28 +0000703
704/*----------------------------------------------------------------*/
705/*--- Sanity checking the data structures ---*/
706/*----------------------------------------------------------------*/
707
708static UWord stats__sanity_checks = 0;
709
sewardjb4112022007-11-09 22:49:28 +0000710static void laog__sanity_check ( Char* who ); /* fwds */
711
712/* REQUIRED INVARIANTS:
713
714 Thread vs Segment/Lock/SecMaps
715
716 for each t in Threads {
717
718 // Thread.lockset: each element is really a valid Lock
719
720 // Thread.lockset: each Lock in set is actually held by that thread
721 for lk in Thread.lockset
722 lk == LockedBy(t)
723
724 // Thread.csegid is a valid SegmentID
725 // and the associated Segment has .thr == t
726
727 }
728
729 all thread Locksets are pairwise empty under intersection
730 (that is, no lock is claimed to be held by more than one thread)
731 -- this is guaranteed if all locks in locksets point back to their
732 owner threads
733
734 Lock vs Thread/Segment/SecMaps
735
736 for each entry (gla, la) in map_locks
737 gla == la->guest_addr
738
739 for each lk in Locks {
740
741 lk->tag is valid
742 lk->guest_addr does not have shadow state NoAccess
743 if lk == LockedBy(t), then t->lockset contains lk
744 if lk == UnlockedBy(segid) then segid is valid SegmentID
745 and can be mapped to a valid Segment(seg)
746 and seg->thr->lockset does not contain lk
747 if lk == UnlockedNew then (no lockset contains lk)
748
749 secmaps for lk has .mbHasLocks == True
750
751 }
752
753 Segment vs Thread/Lock/SecMaps
754
755 the Segment graph is a dag (no cycles)
756 all of the Segment graph must be reachable from the segids
757 mentioned in the Threads
758
759 for seg in Segments {
760
761 seg->thr is a sane Thread
762
763 }
764
765 SecMaps vs Segment/Thread/Lock
766
767 for sm in SecMaps {
768
769 sm properly aligned
770 if any shadow word is ShR or ShM then .mbHasShared == True
771
772 for each Excl(segid) state
773 map_segments_lookup maps to a sane Segment(seg)
774 for each ShM/ShR(tsetid,lsetid) state
775 each lk in lset is a valid Lock
776 each thr in tset is a valid thread, which is non-dead
777
778 }
779*/
780
781
782/* Return True iff 'thr' holds 'lk' in some mode. */
783static Bool thread_is_a_holder_of_Lock ( Thread* thr, Lock* lk )
784{
785 if (lk->heldBy)
sewardj896f6f92008-08-19 08:38:52 +0000786 return VG_(elemBag)( lk->heldBy, (Word)thr ) > 0;
sewardjb4112022007-11-09 22:49:28 +0000787 else
788 return False;
789}
790
791/* Sanity check Threads, as far as possible */
792__attribute__((noinline))
793static void threads__sanity_check ( Char* who )
794{
795#define BAD(_str) do { how = (_str); goto bad; } while (0)
796 Char* how = "no error";
797 Thread* thr;
798 WordSetID wsA, wsW;
sewardj250ec2e2008-02-15 22:02:30 +0000799 UWord* ls_words;
sewardjb4112022007-11-09 22:49:28 +0000800 Word ls_size, i;
801 Lock* lk;
sewardjb4112022007-11-09 22:49:28 +0000802 for (thr = admin_threads; thr; thr = thr->admin) {
sewardjf98e1c02008-10-25 16:22:41 +0000803 if (!HG_(is_sane_Thread)(thr)) BAD("1");
sewardjb4112022007-11-09 22:49:28 +0000804 wsA = thr->locksetA;
805 wsW = thr->locksetW;
806 // locks held in W mode are a subset of all locks held
807 if (!HG_(isSubsetOf)( univ_lsets, wsW, wsA )) BAD("7");
808 HG_(getPayloadWS)( &ls_words, &ls_size, univ_lsets, wsA );
809 for (i = 0; i < ls_size; i++) {
810 lk = (Lock*)ls_words[i];
811 // Thread.lockset: each element is really a valid Lock
sewardjf98e1c02008-10-25 16:22:41 +0000812 if (!HG_(is_sane_LockN)(lk)) BAD("2");
sewardjb4112022007-11-09 22:49:28 +0000813 // Thread.lockset: each Lock in set is actually held by that
814 // thread
815 if (!thread_is_a_holder_of_Lock(thr,lk)) BAD("3");
sewardjb4112022007-11-09 22:49:28 +0000816 }
817 }
818 return;
819 bad:
820 VG_(printf)("threads__sanity_check: who=\"%s\", bad=\"%s\"\n", who, how);
821 tl_assert(0);
822#undef BAD
823}
824
825
826/* Sanity check Locks, as far as possible */
827__attribute__((noinline))
828static void locks__sanity_check ( Char* who )
829{
830#define BAD(_str) do { how = (_str); goto bad; } while (0)
831 Char* how = "no error";
832 Addr gla;
833 Lock* lk;
834 Int i;
835 // # entries in admin_locks == # entries in map_locks
sewardj1d7c3322011-02-28 09:22:51 +0000836 for (i = 0, lk = admin_locks; lk; i++, lk = lk->admin_next)
sewardjb4112022007-11-09 22:49:28 +0000837 ;
sewardj896f6f92008-08-19 08:38:52 +0000838 if (i != VG_(sizeFM)(map_locks)) BAD("1");
sewardjb4112022007-11-09 22:49:28 +0000839 // for each entry (gla, lk) in map_locks
840 // gla == lk->guest_addr
sewardj896f6f92008-08-19 08:38:52 +0000841 VG_(initIterFM)( map_locks );
842 while (VG_(nextIterFM)( map_locks,
sewardjb5f29642007-11-16 12:02:43 +0000843 (Word*)&gla, (Word*)&lk )) {
sewardjb4112022007-11-09 22:49:28 +0000844 if (lk->guestaddr != gla) BAD("2");
845 }
sewardj896f6f92008-08-19 08:38:52 +0000846 VG_(doneIterFM)( map_locks );
sewardjb4112022007-11-09 22:49:28 +0000847 // scan through admin_locks ...
sewardj1d7c3322011-02-28 09:22:51 +0000848 for (lk = admin_locks; lk; lk = lk->admin_next) {
sewardjb4112022007-11-09 22:49:28 +0000849 // lock is sane. Quite comprehensive, also checks that
850 // referenced (holder) threads are sane.
sewardjf98e1c02008-10-25 16:22:41 +0000851 if (!HG_(is_sane_LockN)(lk)) BAD("3");
sewardjb4112022007-11-09 22:49:28 +0000852 // map_locks binds guest address back to this lock
853 if (lk != map_locks_maybe_lookup(lk->guestaddr)) BAD("4");
sewardjb4112022007-11-09 22:49:28 +0000854 // look at all threads mentioned as holders of this lock. Ensure
855 // this lock is mentioned in their locksets.
856 if (lk->heldBy) {
857 Thread* thr;
858 Word count;
sewardj896f6f92008-08-19 08:38:52 +0000859 VG_(initIterBag)( lk->heldBy );
860 while (VG_(nextIterBag)( lk->heldBy,
sewardjb5f29642007-11-16 12:02:43 +0000861 (Word*)&thr, &count )) {
sewardjf98e1c02008-10-25 16:22:41 +0000862 // HG_(is_sane_LockN) above ensures these
sewardjb4112022007-11-09 22:49:28 +0000863 tl_assert(count >= 1);
sewardjf98e1c02008-10-25 16:22:41 +0000864 tl_assert(HG_(is_sane_Thread)(thr));
sewardjb4112022007-11-09 22:49:28 +0000865 if (!HG_(elemWS)(univ_lsets, thr->locksetA, (Word)lk))
866 BAD("6");
867 // also check the w-only lockset
868 if (lk->heldW
869 && !HG_(elemWS)(univ_lsets, thr->locksetW, (Word)lk))
870 BAD("7");
871 if ((!lk->heldW)
872 && HG_(elemWS)(univ_lsets, thr->locksetW, (Word)lk))
873 BAD("8");
874 }
sewardj896f6f92008-08-19 08:38:52 +0000875 VG_(doneIterBag)( lk->heldBy );
sewardjb4112022007-11-09 22:49:28 +0000876 } else {
877 /* lock not held by anybody */
878 if (lk->heldW) BAD("9"); /* should be False if !heldBy */
879 // since lk is unheld, then (no lockset contains lk)
880 // hmm, this is really too expensive to check. Hmm.
881 }
sewardjb4112022007-11-09 22:49:28 +0000882 }
883
884 return;
885 bad:
886 VG_(printf)("locks__sanity_check: who=\"%s\", bad=\"%s\"\n", who, how);
887 tl_assert(0);
888#undef BAD
889}
890
891
sewardjb4112022007-11-09 22:49:28 +0000892static void all_except_Locks__sanity_check ( Char* who ) {
893 stats__sanity_checks++;
894 if (0) VG_(printf)("all_except_Locks__sanity_check(%s)\n", who);
895 threads__sanity_check(who);
sewardjc1fb9d22011-02-28 09:03:44 +0000896 if (HG_(clo_track_lockorders))
897 laog__sanity_check(who);
sewardjb4112022007-11-09 22:49:28 +0000898}
899static void all__sanity_check ( Char* who ) {
900 all_except_Locks__sanity_check(who);
901 locks__sanity_check(who);
902}
903
904
905/*----------------------------------------------------------------*/
sewardjb4112022007-11-09 22:49:28 +0000906/*--- Shadow value and address range handlers ---*/
907/*----------------------------------------------------------------*/
908
909static void laog__pre_thread_acquires_lock ( Thread*, Lock* ); /* fwds */
sewardj1cbc12f2008-11-10 16:16:46 +0000910//static void laog__handle_lock_deletions ( WordSetID ); /* fwds */
sewardjb4112022007-11-09 22:49:28 +0000911static inline Thread* get_current_Thread ( void ); /* fwds */
sewardj1cbc12f2008-11-10 16:16:46 +0000912__attribute__((noinline))
913static void laog__handle_one_lock_deletion ( Lock* lk ); /* fwds */
sewardjb4112022007-11-09 22:49:28 +0000914
sewardjb4112022007-11-09 22:49:28 +0000915
916/* Block-copy states (needed for implementing realloc()). */
sewardj23f12002009-07-24 08:45:08 +0000917/* FIXME this copies shadow memory; it doesn't apply the MSM to it.
918 Is that a problem? (hence 'scopy' rather than 'ccopy') */
919static void shadow_mem_scopy_range ( Thread* thr,
920 Addr src, Addr dst, SizeT len )
sewardjf98e1c02008-10-25 16:22:41 +0000921{
922 Thr* hbthr = thr->hbthr;
923 tl_assert(hbthr);
sewardj23f12002009-07-24 08:45:08 +0000924 libhb_copy_shadow_state( hbthr, src, dst, len );
sewardjb4112022007-11-09 22:49:28 +0000925}
926
sewardj23f12002009-07-24 08:45:08 +0000927static void shadow_mem_cread_range ( Thread* thr, Addr a, SizeT len )
928{
sewardjf98e1c02008-10-25 16:22:41 +0000929 Thr* hbthr = thr->hbthr;
930 tl_assert(hbthr);
sewardj23f12002009-07-24 08:45:08 +0000931 LIBHB_CREAD_N(hbthr, a, len);
932}
933
934static void shadow_mem_cwrite_range ( Thread* thr, Addr a, SizeT len ) {
935 Thr* hbthr = thr->hbthr;
936 tl_assert(hbthr);
937 LIBHB_CWRITE_N(hbthr, a, len);
sewardjb4112022007-11-09 22:49:28 +0000938}
939
940static void shadow_mem_make_New ( Thread* thr, Addr a, SizeT len )
941{
sewardj23f12002009-07-24 08:45:08 +0000942 libhb_srange_new( thr->hbthr, a, len );
sewardjb4112022007-11-09 22:49:28 +0000943}
944
sewardjfd35d492011-03-17 19:39:55 +0000945static void shadow_mem_make_NoAccess_NoFX ( Thread* thr, Addr aIN, SizeT len )
sewardjb4112022007-11-09 22:49:28 +0000946{
sewardjb4112022007-11-09 22:49:28 +0000947 if (0 && len > 500)
sewardjfd35d492011-03-17 19:39:55 +0000948 VG_(printf)("make NoAccess_NoFX ( %#lx, %ld )\n", aIN, len );
949 // has no effect (NoFX)
950 libhb_srange_noaccess_NoFX( thr->hbthr, aIN, len );
951}
952
953static void shadow_mem_make_NoAccess_AHAE ( Thread* thr, Addr aIN, SizeT len )
954{
955 if (0 && len > 500)
956 VG_(printf)("make NoAccess_AHAE ( %#lx, %ld )\n", aIN, len );
957 // Actually Has An Effect (AHAE)
958 libhb_srange_noaccess_AHAE( thr->hbthr, aIN, len );
sewardjb4112022007-11-09 22:49:28 +0000959}
960
sewardj406bac82010-03-03 23:03:40 +0000961static void shadow_mem_make_Untracked ( Thread* thr, Addr aIN, SizeT len )
962{
963 if (0 && len > 500)
964 VG_(printf)("make Untracked ( %#lx, %ld )\n", aIN, len );
965 libhb_srange_untrack( thr->hbthr, aIN, len );
966}
967
sewardjb4112022007-11-09 22:49:28 +0000968
969/*----------------------------------------------------------------*/
970/*--- Event handlers (evh__* functions) ---*/
971/*--- plus helpers (evhH__* functions) ---*/
972/*----------------------------------------------------------------*/
973
974/*--------- Event handler helpers (evhH__* functions) ---------*/
975
976/* Create a new segment for 'thr', making it depend (.prev) on its
977 existing segment, bind together the SegmentID and Segment, and
978 return both of them. Also update 'thr' so it references the new
979 Segment. */
sewardjf98e1c02008-10-25 16:22:41 +0000980//zz static
981//zz void evhH__start_new_segment_for_thread ( /*OUT*/SegmentID* new_segidP,
982//zz /*OUT*/Segment** new_segP,
983//zz Thread* thr )
984//zz {
985//zz Segment* cur_seg;
986//zz tl_assert(new_segP);
987//zz tl_assert(new_segidP);
988//zz tl_assert(HG_(is_sane_Thread)(thr));
989//zz cur_seg = map_segments_lookup( thr->csegid );
990//zz tl_assert(cur_seg);
991//zz tl_assert(cur_seg->thr == thr); /* all sane segs should point back
992//zz at their owner thread. */
993//zz *new_segP = mk_Segment( thr, cur_seg, NULL/*other*/ );
994//zz *new_segidP = alloc_SegmentID();
995//zz map_segments_add( *new_segidP, *new_segP );
996//zz thr->csegid = *new_segidP;
997//zz }
sewardjb4112022007-11-09 22:49:28 +0000998
999
1000/* The lock at 'lock_ga' has acquired a writer. Make all necessary
1001 updates, and also do all possible error checks. */
1002static
1003void evhH__post_thread_w_acquires_lock ( Thread* thr,
1004 LockKind lkk, Addr lock_ga )
1005{
1006 Lock* lk;
1007
1008 /* Basically what we need to do is call lockN_acquire_writer.
1009 However, that will barf if any 'invalid' lock states would
1010 result. Therefore check before calling. Side effect is that
sewardjf98e1c02008-10-25 16:22:41 +00001011 'HG_(is_sane_LockN)(lk)' is both a pre- and post-condition of this
sewardjb4112022007-11-09 22:49:28 +00001012 routine.
1013
1014 Because this routine is only called after successful lock
1015 acquisition, we should not be asked to move the lock into any
1016 invalid states. Requests to do so are bugs in libpthread, since
1017 that should have rejected any such requests. */
1018
sewardjf98e1c02008-10-25 16:22:41 +00001019 tl_assert(HG_(is_sane_Thread)(thr));
sewardjb4112022007-11-09 22:49:28 +00001020 /* Try to find the lock. If we can't, then create a new one with
1021 kind 'lkk'. */
1022 lk = map_locks_lookup_or_create(
1023 lkk, lock_ga, map_threads_reverse_lookup_SLOW(thr) );
sewardjf98e1c02008-10-25 16:22:41 +00001024 tl_assert( HG_(is_sane_LockN)(lk) );
1025
1026 /* check libhb level entities exist */
1027 tl_assert(thr->hbthr);
1028 tl_assert(lk->hbso);
sewardjb4112022007-11-09 22:49:28 +00001029
1030 if (lk->heldBy == NULL) {
1031 /* the lock isn't held. Simple. */
1032 tl_assert(!lk->heldW);
1033 lockN_acquire_writer( lk, thr );
sewardjf98e1c02008-10-25 16:22:41 +00001034 /* acquire a dependency from the lock's VCs */
1035 libhb_so_recv( thr->hbthr, lk->hbso, True/*strong_recv*/ );
sewardjb4112022007-11-09 22:49:28 +00001036 goto noerror;
1037 }
1038
1039 /* So the lock is already held. If held as a r-lock then
1040 libpthread must be buggy. */
1041 tl_assert(lk->heldBy);
1042 if (!lk->heldW) {
sewardjf98e1c02008-10-25 16:22:41 +00001043 HG_(record_error_Misc)(
1044 thr, "Bug in libpthread: write lock "
1045 "granted on rwlock which is currently rd-held");
sewardjb4112022007-11-09 22:49:28 +00001046 goto error;
1047 }
1048
1049 /* So the lock is held in w-mode. If it's held by some other
1050 thread, then libpthread must be buggy. */
sewardj896f6f92008-08-19 08:38:52 +00001051 tl_assert(VG_(sizeUniqueBag)(lk->heldBy) == 1); /* from precondition */
sewardjb4112022007-11-09 22:49:28 +00001052
sewardj896f6f92008-08-19 08:38:52 +00001053 if (thr != (Thread*)VG_(anyElementOfBag)(lk->heldBy)) {
sewardjf98e1c02008-10-25 16:22:41 +00001054 HG_(record_error_Misc)(
1055 thr, "Bug in libpthread: write lock "
1056 "granted on mutex/rwlock which is currently "
1057 "wr-held by a different thread");
sewardjb4112022007-11-09 22:49:28 +00001058 goto error;
1059 }
1060
1061 /* So the lock is already held in w-mode by 'thr'. That means this
1062 is an attempt to lock it recursively, which is only allowable
1063 for LK_mbRec kinded locks. Since this routine is called only
1064 once the lock has been acquired, this must also be a libpthread
1065 bug. */
1066 if (lk->kind != LK_mbRec) {
sewardjf98e1c02008-10-25 16:22:41 +00001067 HG_(record_error_Misc)(
1068 thr, "Bug in libpthread: recursive write lock "
1069 "granted on mutex/wrlock which does not "
1070 "support recursion");
sewardjb4112022007-11-09 22:49:28 +00001071 goto error;
1072 }
1073
1074 /* So we are recursively re-locking a lock we already w-hold. */
1075 lockN_acquire_writer( lk, thr );
sewardjf98e1c02008-10-25 16:22:41 +00001076 /* acquire a dependency from the lock's VC. Probably pointless,
1077 but also harmless. */
1078 libhb_so_recv( thr->hbthr, lk->hbso, True/*strong_recv*/ );
sewardjb4112022007-11-09 22:49:28 +00001079 goto noerror;
1080
1081 noerror:
sewardjc1fb9d22011-02-28 09:03:44 +00001082 if (HG_(clo_track_lockorders)) {
1083 /* check lock order acquisition graph, and update. This has to
1084 happen before the lock is added to the thread's locksetA/W. */
1085 laog__pre_thread_acquires_lock( thr, lk );
1086 }
sewardjb4112022007-11-09 22:49:28 +00001087 /* update the thread's held-locks set */
1088 thr->locksetA = HG_(addToWS)( univ_lsets, thr->locksetA, (Word)lk );
1089 thr->locksetW = HG_(addToWS)( univ_lsets, thr->locksetW, (Word)lk );
1090 /* fall through */
1091
1092 error:
sewardjf98e1c02008-10-25 16:22:41 +00001093 tl_assert(HG_(is_sane_LockN)(lk));
sewardjb4112022007-11-09 22:49:28 +00001094}
1095
1096
1097/* The lock at 'lock_ga' has acquired a reader. Make all necessary
1098 updates, and also do all possible error checks. */
1099static
1100void evhH__post_thread_r_acquires_lock ( Thread* thr,
1101 LockKind lkk, Addr lock_ga )
1102{
1103 Lock* lk;
1104
1105 /* Basically what we need to do is call lockN_acquire_reader.
1106 However, that will barf if any 'invalid' lock states would
1107 result. Therefore check before calling. Side effect is that
sewardjf98e1c02008-10-25 16:22:41 +00001108 'HG_(is_sane_LockN)(lk)' is both a pre- and post-condition of this
sewardjb4112022007-11-09 22:49:28 +00001109 routine.
1110
1111 Because this routine is only called after successful lock
1112 acquisition, we should not be asked to move the lock into any
1113 invalid states. Requests to do so are bugs in libpthread, since
1114 that should have rejected any such requests. */
1115
sewardjf98e1c02008-10-25 16:22:41 +00001116 tl_assert(HG_(is_sane_Thread)(thr));
sewardjb4112022007-11-09 22:49:28 +00001117 /* Try to find the lock. If we can't, then create a new one with
1118 kind 'lkk'. Only a reader-writer lock can be read-locked,
1119 hence the first assertion. */
1120 tl_assert(lkk == LK_rdwr);
1121 lk = map_locks_lookup_or_create(
1122 lkk, lock_ga, map_threads_reverse_lookup_SLOW(thr) );
sewardjf98e1c02008-10-25 16:22:41 +00001123 tl_assert( HG_(is_sane_LockN)(lk) );
1124
1125 /* check libhb level entities exist */
1126 tl_assert(thr->hbthr);
1127 tl_assert(lk->hbso);
sewardjb4112022007-11-09 22:49:28 +00001128
1129 if (lk->heldBy == NULL) {
1130 /* the lock isn't held. Simple. */
1131 tl_assert(!lk->heldW);
1132 lockN_acquire_reader( lk, thr );
sewardjf98e1c02008-10-25 16:22:41 +00001133 /* acquire a dependency from the lock's VC */
1134 libhb_so_recv( thr->hbthr, lk->hbso, False/*!strong_recv*/ );
sewardjb4112022007-11-09 22:49:28 +00001135 goto noerror;
1136 }
1137
1138 /* So the lock is already held. If held as a w-lock then
1139 libpthread must be buggy. */
1140 tl_assert(lk->heldBy);
1141 if (lk->heldW) {
sewardjf98e1c02008-10-25 16:22:41 +00001142 HG_(record_error_Misc)( thr, "Bug in libpthread: read lock "
1143 "granted on rwlock which is "
1144 "currently wr-held");
sewardjb4112022007-11-09 22:49:28 +00001145 goto error;
1146 }
1147
1148 /* Easy enough. In short anybody can get a read-lock on a rwlock
1149 provided it is either unlocked or already in rd-held. */
1150 lockN_acquire_reader( lk, thr );
sewardjf98e1c02008-10-25 16:22:41 +00001151 /* acquire a dependency from the lock's VC. Probably pointless,
1152 but also harmless. */
1153 libhb_so_recv( thr->hbthr, lk->hbso, False/*!strong_recv*/ );
sewardjb4112022007-11-09 22:49:28 +00001154 goto noerror;
1155
1156 noerror:
sewardjc1fb9d22011-02-28 09:03:44 +00001157 if (HG_(clo_track_lockorders)) {
1158 /* check lock order acquisition graph, and update. This has to
1159 happen before the lock is added to the thread's locksetA/W. */
1160 laog__pre_thread_acquires_lock( thr, lk );
1161 }
sewardjb4112022007-11-09 22:49:28 +00001162 /* update the thread's held-locks set */
1163 thr->locksetA = HG_(addToWS)( univ_lsets, thr->locksetA, (Word)lk );
1164 /* but don't update thr->locksetW, since lk is only rd-held */
1165 /* fall through */
1166
1167 error:
sewardjf98e1c02008-10-25 16:22:41 +00001168 tl_assert(HG_(is_sane_LockN)(lk));
sewardjb4112022007-11-09 22:49:28 +00001169}
1170
1171
1172/* The lock at 'lock_ga' is just about to be unlocked. Make all
1173 necessary updates, and also do all possible error checks. */
1174static
1175void evhH__pre_thread_releases_lock ( Thread* thr,
1176 Addr lock_ga, Bool isRDWR )
1177{
1178 Lock* lock;
1179 Word n;
sewardjf98e1c02008-10-25 16:22:41 +00001180 Bool was_heldW;
sewardjb4112022007-11-09 22:49:28 +00001181
1182 /* This routine is called prior to a lock release, before
1183 libpthread has had a chance to validate the call. Hence we need
1184 to detect and reject any attempts to move the lock into an
1185 invalid state. Such attempts are bugs in the client.
1186
1187 isRDWR is True if we know from the wrapper context that lock_ga
1188 should refer to a reader-writer lock, and is False if [ditto]
1189 lock_ga should refer to a standard mutex. */
1190
sewardjf98e1c02008-10-25 16:22:41 +00001191 tl_assert(HG_(is_sane_Thread)(thr));
sewardjb4112022007-11-09 22:49:28 +00001192 lock = map_locks_maybe_lookup( lock_ga );
1193
1194 if (!lock) {
1195 /* We know nothing about a lock at 'lock_ga'. Nevertheless
1196 the client is trying to unlock it. So complain, then ignore
1197 the attempt. */
sewardjf98e1c02008-10-25 16:22:41 +00001198 HG_(record_error_UnlockBogus)( thr, lock_ga );
sewardjb4112022007-11-09 22:49:28 +00001199 return;
1200 }
1201
1202 tl_assert(lock->guestaddr == lock_ga);
sewardjf98e1c02008-10-25 16:22:41 +00001203 tl_assert(HG_(is_sane_LockN)(lock));
sewardjb4112022007-11-09 22:49:28 +00001204
1205 if (isRDWR && lock->kind != LK_rdwr) {
sewardjf98e1c02008-10-25 16:22:41 +00001206 HG_(record_error_Misc)( thr, "pthread_rwlock_unlock with a "
1207 "pthread_mutex_t* argument " );
sewardjb4112022007-11-09 22:49:28 +00001208 }
1209 if ((!isRDWR) && lock->kind == LK_rdwr) {
sewardjf98e1c02008-10-25 16:22:41 +00001210 HG_(record_error_Misc)( thr, "pthread_mutex_unlock with a "
1211 "pthread_rwlock_t* argument " );
sewardjb4112022007-11-09 22:49:28 +00001212 }
1213
1214 if (!lock->heldBy) {
1215 /* The lock is not held. This indicates a serious bug in the
1216 client. */
1217 tl_assert(!lock->heldW);
sewardjf98e1c02008-10-25 16:22:41 +00001218 HG_(record_error_UnlockUnlocked)( thr, lock );
sewardjb4112022007-11-09 22:49:28 +00001219 tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetA, (Word)lock ));
1220 tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetW, (Word)lock ));
1221 goto error;
1222 }
1223
sewardjf98e1c02008-10-25 16:22:41 +00001224 /* test just above dominates */
1225 tl_assert(lock->heldBy);
1226 was_heldW = lock->heldW;
1227
sewardjb4112022007-11-09 22:49:28 +00001228 /* The lock is held. Is this thread one of the holders? If not,
1229 report a bug in the client. */
sewardj896f6f92008-08-19 08:38:52 +00001230 n = VG_(elemBag)( lock->heldBy, (Word)thr );
sewardjb4112022007-11-09 22:49:28 +00001231 tl_assert(n >= 0);
1232 if (n == 0) {
1233 /* We are not a current holder of the lock. This is a bug in
1234 the guest, and (per POSIX pthread rules) the unlock
1235 attempt will fail. So just complain and do nothing
1236 else. */
sewardj896f6f92008-08-19 08:38:52 +00001237 Thread* realOwner = (Thread*)VG_(anyElementOfBag)( lock->heldBy );
sewardjf98e1c02008-10-25 16:22:41 +00001238 tl_assert(HG_(is_sane_Thread)(realOwner));
sewardjb4112022007-11-09 22:49:28 +00001239 tl_assert(realOwner != thr);
1240 tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetA, (Word)lock ));
1241 tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetW, (Word)lock ));
sewardjf98e1c02008-10-25 16:22:41 +00001242 HG_(record_error_UnlockForeign)( thr, realOwner, lock );
sewardjb4112022007-11-09 22:49:28 +00001243 goto error;
1244 }
1245
1246 /* Ok, we hold the lock 'n' times. */
1247 tl_assert(n >= 1);
1248
1249 lockN_release( lock, thr );
1250
1251 n--;
1252 tl_assert(n >= 0);
1253
1254 if (n > 0) {
1255 tl_assert(lock->heldBy);
sewardj896f6f92008-08-19 08:38:52 +00001256 tl_assert(n == VG_(elemBag)( lock->heldBy, (Word)thr ));
sewardjb4112022007-11-09 22:49:28 +00001257 /* We still hold the lock. So either it's a recursive lock
1258 or a rwlock which is currently r-held. */
1259 tl_assert(lock->kind == LK_mbRec
1260 || (lock->kind == LK_rdwr && !lock->heldW));
1261 tl_assert(HG_(elemWS)( univ_lsets, thr->locksetA, (Word)lock ));
1262 if (lock->heldW)
1263 tl_assert(HG_(elemWS)( univ_lsets, thr->locksetW, (Word)lock ));
1264 else
1265 tl_assert(!HG_(elemWS)( univ_lsets, thr->locksetW, (Word)lock ));
1266 } else {
sewardj983f3022009-05-21 14:49:55 +00001267 /* n is zero. This means we don't hold the lock any more. But
1268 if it's a rwlock held in r-mode, someone else could still
1269 hold it. Just do whatever sanity checks we can. */
1270 if (lock->kind == LK_rdwr && lock->heldBy) {
1271 /* It's a rwlock. We no longer hold it but we used to;
1272 nevertheless it still appears to be held by someone else.
1273 The implication is that, prior to this release, it must
1274 have been shared by us and and whoever else is holding it;
1275 which in turn implies it must be r-held, since a lock
1276 can't be w-held by more than one thread. */
1277 /* The lock is now R-held by somebody else: */
1278 tl_assert(lock->heldW == False);
1279 } else {
1280 /* Normal case. It's either not a rwlock, or it's a rwlock
1281 that we used to hold in w-mode (which is pretty much the
1282 same thing as a non-rwlock.) Since this transaction is
1283 atomic (V does not allow multiple threads to run
1284 simultaneously), it must mean the lock is now not held by
1285 anybody. Hence assert for it. */
1286 /* The lock is now not held by anybody: */
1287 tl_assert(!lock->heldBy);
1288 tl_assert(lock->heldW == False);
1289 }
sewardjf98e1c02008-10-25 16:22:41 +00001290 //if (lock->heldBy) {
1291 // tl_assert(0 == VG_(elemBag)( lock->heldBy, (Word)thr ));
1292 //}
sewardjb4112022007-11-09 22:49:28 +00001293 /* update this thread's lockset accordingly. */
1294 thr->locksetA
1295 = HG_(delFromWS)( univ_lsets, thr->locksetA, (Word)lock );
1296 thr->locksetW
1297 = HG_(delFromWS)( univ_lsets, thr->locksetW, (Word)lock );
sewardjf98e1c02008-10-25 16:22:41 +00001298 /* push our VC into the lock */
1299 tl_assert(thr->hbthr);
1300 tl_assert(lock->hbso);
1301 /* If the lock was previously W-held, then we want to do a
1302 strong send, and if previously R-held, then a weak send. */
1303 libhb_so_send( thr->hbthr, lock->hbso, was_heldW );
sewardjb4112022007-11-09 22:49:28 +00001304 }
1305 /* fall through */
1306
1307 error:
sewardjf98e1c02008-10-25 16:22:41 +00001308 tl_assert(HG_(is_sane_LockN)(lock));
sewardjb4112022007-11-09 22:49:28 +00001309}
1310
1311
sewardj9f569b72008-11-13 13:33:09 +00001312/* ---------------------------------------------------------- */
1313/* -------- Event handlers proper (evh__* functions) -------- */
1314/* ---------------------------------------------------------- */
sewardjb4112022007-11-09 22:49:28 +00001315
1316/* What is the Thread* for the currently running thread? This is
1317 absolutely performance critical. We receive notifications from the
1318 core for client code starts/stops, and cache the looked-up result
1319 in 'current_Thread'. Hence, for the vast majority of requests,
1320 finding the current thread reduces to a read of a global variable,
1321 provided get_current_Thread_in_C_C is inlined.
1322
1323 Outside of client code, current_Thread is NULL, and presumably
1324 any uses of it will cause a segfault. Hence:
1325
1326 - for uses definitely within client code, use
1327 get_current_Thread_in_C_C.
1328
1329 - for all other uses, use get_current_Thread.
1330*/
1331
sewardj23f12002009-07-24 08:45:08 +00001332static Thread *current_Thread = NULL,
1333 *current_Thread_prev = NULL;
sewardjb4112022007-11-09 22:49:28 +00001334
1335static void evh__start_client_code ( ThreadId tid, ULong nDisp ) {
1336 if (0) VG_(printf)("start %d %llu\n", (Int)tid, nDisp);
1337 tl_assert(current_Thread == NULL);
1338 current_Thread = map_threads_lookup( tid );
1339 tl_assert(current_Thread != NULL);
sewardj23f12002009-07-24 08:45:08 +00001340 if (current_Thread != current_Thread_prev) {
1341 libhb_Thr_resumes( current_Thread->hbthr );
1342 current_Thread_prev = current_Thread;
1343 }
sewardjb4112022007-11-09 22:49:28 +00001344}
1345static void evh__stop_client_code ( ThreadId tid, ULong nDisp ) {
1346 if (0) VG_(printf)(" stop %d %llu\n", (Int)tid, nDisp);
1347 tl_assert(current_Thread != NULL);
1348 current_Thread = NULL;
sewardjf98e1c02008-10-25 16:22:41 +00001349 libhb_maybe_GC();
sewardjb4112022007-11-09 22:49:28 +00001350}
1351static inline Thread* get_current_Thread_in_C_C ( void ) {
1352 return current_Thread;
1353}
1354static inline Thread* get_current_Thread ( void ) {
1355 ThreadId coretid;
1356 Thread* thr;
1357 thr = get_current_Thread_in_C_C();
1358 if (LIKELY(thr))
1359 return thr;
1360 /* evidently not in client code. Do it the slow way. */
1361 coretid = VG_(get_running_tid)();
1362 /* FIXME: get rid of the following kludge. It exists because
sewardjf98e1c02008-10-25 16:22:41 +00001363 evh__new_mem is called during initialisation (as notification
sewardjb4112022007-11-09 22:49:28 +00001364 of initial memory layout) and VG_(get_running_tid)() returns
1365 VG_INVALID_THREADID at that point. */
1366 if (coretid == VG_INVALID_THREADID)
1367 coretid = 1; /* KLUDGE */
1368 thr = map_threads_lookup( coretid );
1369 return thr;
1370}
1371
1372static
1373void evh__new_mem ( Addr a, SizeT len ) {
1374 if (SHOW_EVENTS >= 2)
1375 VG_(printf)("evh__new_mem(%p, %lu)\n", (void*)a, len );
1376 shadow_mem_make_New( get_current_Thread(), a, len );
sewardjf98e1c02008-10-25 16:22:41 +00001377 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
sewardjb4112022007-11-09 22:49:28 +00001378 all__sanity_check("evh__new_mem-post");
1379}
1380
1381static
sewardj1f77fec2010-04-12 19:51:04 +00001382void evh__new_mem_stack ( Addr a, SizeT len ) {
1383 if (SHOW_EVENTS >= 2)
1384 VG_(printf)("evh__new_mem_stack(%p, %lu)\n", (void*)a, len );
1385 shadow_mem_make_New( get_current_Thread(),
1386 -VG_STACK_REDZONE_SZB + a, len );
1387 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1388 all__sanity_check("evh__new_mem_stack-post");
1389}
1390
1391static
sewardj7cf4e6b2008-05-01 20:24:26 +00001392void evh__new_mem_w_tid ( Addr a, SizeT len, ThreadId tid ) {
1393 if (SHOW_EVENTS >= 2)
1394 VG_(printf)("evh__new_mem_w_tid(%p, %lu)\n", (void*)a, len );
1395 shadow_mem_make_New( get_current_Thread(), a, len );
sewardjf98e1c02008-10-25 16:22:41 +00001396 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
sewardj7cf4e6b2008-05-01 20:24:26 +00001397 all__sanity_check("evh__new_mem_w_tid-post");
1398}
1399
1400static
sewardjb4112022007-11-09 22:49:28 +00001401void evh__new_mem_w_perms ( Addr a, SizeT len,
sewardj9c606bd2008-09-18 18:12:50 +00001402 Bool rr, Bool ww, Bool xx, ULong di_handle ) {
sewardjb4112022007-11-09 22:49:28 +00001403 if (SHOW_EVENTS >= 1)
1404 VG_(printf)("evh__new_mem_w_perms(%p, %lu, %d,%d,%d)\n",
1405 (void*)a, len, (Int)rr, (Int)ww, (Int)xx );
1406 if (rr || ww || xx)
1407 shadow_mem_make_New( get_current_Thread(), a, len );
sewardjf98e1c02008-10-25 16:22:41 +00001408 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
sewardjb4112022007-11-09 22:49:28 +00001409 all__sanity_check("evh__new_mem_w_perms-post");
1410}
1411
1412static
1413void evh__set_perms ( Addr a, SizeT len,
1414 Bool rr, Bool ww, Bool xx ) {
sewardjfd35d492011-03-17 19:39:55 +00001415 // This handles mprotect requests. If the memory is being put
1416 // into no-R no-W state, paint it as NoAccess, for the reasons
1417 // documented at evh__die_mem_munmap().
sewardjb4112022007-11-09 22:49:28 +00001418 if (SHOW_EVENTS >= 1)
sewardjfd35d492011-03-17 19:39:55 +00001419 VG_(printf)("evh__set_perms(%p, %lu, r=%d w=%d x=%d)\n",
sewardjb4112022007-11-09 22:49:28 +00001420 (void*)a, len, (Int)rr, (Int)ww, (Int)xx );
1421 /* Hmm. What should we do here, that actually makes any sense?
1422 Let's say: if neither readable nor writable, then declare it
1423 NoAccess, else leave it alone. */
1424 if (!(rr || ww))
sewardjfd35d492011-03-17 19:39:55 +00001425 shadow_mem_make_NoAccess_AHAE( get_current_Thread(), a, len );
sewardjf98e1c02008-10-25 16:22:41 +00001426 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
sewardjb4112022007-11-09 22:49:28 +00001427 all__sanity_check("evh__set_perms-post");
1428}
1429
1430static
1431void evh__die_mem ( Addr a, SizeT len ) {
sewardjfd35d492011-03-17 19:39:55 +00001432 // Urr, libhb ignores this.
sewardjb4112022007-11-09 22:49:28 +00001433 if (SHOW_EVENTS >= 2)
1434 VG_(printf)("evh__die_mem(%p, %lu)\n", (void*)a, len );
sewardjfd35d492011-03-17 19:39:55 +00001435 shadow_mem_make_NoAccess_NoFX( get_current_Thread(), a, len );
sewardjf98e1c02008-10-25 16:22:41 +00001436 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
sewardjb4112022007-11-09 22:49:28 +00001437 all__sanity_check("evh__die_mem-post");
1438}
1439
1440static
sewardjfd35d492011-03-17 19:39:55 +00001441void evh__die_mem_munmap ( Addr a, SizeT len ) {
1442 // It's important that libhb doesn't ignore this. If, as is likely,
1443 // the client is subject to address space layout randomization,
1444 // then unmapped areas may never get remapped over, even in long
1445 // runs. If we just ignore them we wind up with large resource
1446 // (VTS) leaks in libhb. So force them to NoAccess, so that all
1447 // VTS references in the affected area are dropped. Marking memory
1448 // as NoAccess is expensive, but we assume that munmap is sufficiently
1449 // rare that the space gains of doing this are worth the costs.
1450 if (SHOW_EVENTS >= 2)
1451 VG_(printf)("evh__die_mem_munmap(%p, %lu)\n", (void*)a, len );
1452 shadow_mem_make_NoAccess_AHAE( get_current_Thread(), a, len );
1453}
1454
1455static
sewardj406bac82010-03-03 23:03:40 +00001456void evh__untrack_mem ( Addr a, SizeT len ) {
sewardjfd35d492011-03-17 19:39:55 +00001457 // Libhb doesn't ignore this.
sewardj406bac82010-03-03 23:03:40 +00001458 if (SHOW_EVENTS >= 2)
1459 VG_(printf)("evh__untrack_mem(%p, %lu)\n", (void*)a, len );
1460 shadow_mem_make_Untracked( get_current_Thread(), a, len );
1461 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1462 all__sanity_check("evh__untrack_mem-post");
1463}
1464
1465static
sewardj23f12002009-07-24 08:45:08 +00001466void evh__copy_mem ( Addr src, Addr dst, SizeT len ) {
1467 if (SHOW_EVENTS >= 2)
1468 VG_(printf)("evh__copy_mem(%p, %p, %lu)\n", (void*)src, (void*)dst, len );
1469 shadow_mem_scopy_range( get_current_Thread(), src, dst, len );
1470 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
1471 all__sanity_check("evh__copy_mem-post");
1472}
1473
1474static
sewardjb4112022007-11-09 22:49:28 +00001475void evh__pre_thread_ll_create ( ThreadId parent, ThreadId child )
1476{
1477 if (SHOW_EVENTS >= 1)
1478 VG_(printf)("evh__pre_thread_ll_create(p=%d, c=%d)\n",
1479 (Int)parent, (Int)child );
1480
1481 if (parent != VG_INVALID_THREADID) {
sewardjf98e1c02008-10-25 16:22:41 +00001482 Thread* thr_p;
1483 Thread* thr_c;
1484 Thr* hbthr_p;
1485 Thr* hbthr_c;
sewardjb4112022007-11-09 22:49:28 +00001486
sewardjf98e1c02008-10-25 16:22:41 +00001487 tl_assert(HG_(is_sane_ThreadId)(parent));
1488 tl_assert(HG_(is_sane_ThreadId)(child));
sewardjb4112022007-11-09 22:49:28 +00001489 tl_assert(parent != child);
1490
1491 thr_p = map_threads_maybe_lookup( parent );
1492 thr_c = map_threads_maybe_lookup( child );
1493
1494 tl_assert(thr_p != NULL);
1495 tl_assert(thr_c == NULL);
1496
sewardjf98e1c02008-10-25 16:22:41 +00001497 hbthr_p = thr_p->hbthr;
1498 tl_assert(hbthr_p != NULL);
sewardj60626642011-03-10 15:14:37 +00001499 tl_assert( libhb_get_Thr_hgthread(hbthr_p) == thr_p );
sewardjb4112022007-11-09 22:49:28 +00001500
sewardjf98e1c02008-10-25 16:22:41 +00001501 hbthr_c = libhb_create ( hbthr_p );
1502
1503 /* Create a new thread record for the child. */
sewardjb4112022007-11-09 22:49:28 +00001504 /* a Thread for the new thread ... */
sewardjf98e1c02008-10-25 16:22:41 +00001505 thr_c = mk_Thread( hbthr_c );
sewardj60626642011-03-10 15:14:37 +00001506 tl_assert( libhb_get_Thr_hgthread(hbthr_c) == NULL );
1507 libhb_set_Thr_hgthread(hbthr_c, thr_c);
sewardjb4112022007-11-09 22:49:28 +00001508
1509 /* and bind it in the thread-map table */
1510 map_threads[child] = thr_c;
sewardjf98e1c02008-10-25 16:22:41 +00001511 tl_assert(thr_c->coretid == VG_INVALID_THREADID);
1512 thr_c->coretid = child;
sewardjb4112022007-11-09 22:49:28 +00001513
1514 /* Record where the parent is so we can later refer to this in
1515 error messages.
1516
1517 On amd64-linux, this entails a nasty glibc-2.5 specific hack.
1518 The stack snapshot is taken immediately after the parent has
1519 returned from its sys_clone call. Unfortunately there is no
1520 unwind info for the insn following "syscall" - reading the
1521 glibc sources confirms this. So we ask for a snapshot to be
1522 taken as if RIP was 3 bytes earlier, in a place where there
1523 is unwind info. Sigh.
1524 */
1525 { Word first_ip_delta = 0;
1526# if defined(VGP_amd64_linux)
1527 first_ip_delta = -3;
1528# endif
1529 thr_c->created_at = VG_(record_ExeContext)(parent, first_ip_delta);
1530 }
sewardjb4112022007-11-09 22:49:28 +00001531 }
1532
sewardjf98e1c02008-10-25 16:22:41 +00001533 if (HG_(clo_sanity_flags) & SCE_THREADS)
sewardjb4112022007-11-09 22:49:28 +00001534 all__sanity_check("evh__pre_thread_create-post");
1535}
1536
1537static
1538void evh__pre_thread_ll_exit ( ThreadId quit_tid )
1539{
1540 Int nHeld;
1541 Thread* thr_q;
1542 if (SHOW_EVENTS >= 1)
1543 VG_(printf)("evh__pre_thread_ll_exit(thr=%d)\n",
1544 (Int)quit_tid );
1545
1546 /* quit_tid has disappeared without joining to any other thread.
1547 Therefore there is no synchronisation event associated with its
1548 exit and so we have to pretty much treat it as if it was still
1549 alive but mysteriously making no progress. That is because, if
1550 we don't know when it really exited, then we can never say there
1551 is a point in time when we're sure the thread really has
1552 finished, and so we need to consider the possibility that it
1553 lingers indefinitely and continues to interact with other
1554 threads. */
1555 /* However, it might have rendezvous'd with a thread that called
1556 pthread_join with this one as arg, prior to this point (that's
1557 how NPTL works). In which case there has already been a prior
1558 sync event. So in any case, just let the thread exit. On NPTL,
1559 all thread exits go through here. */
sewardjf98e1c02008-10-25 16:22:41 +00001560 tl_assert(HG_(is_sane_ThreadId)(quit_tid));
sewardjb4112022007-11-09 22:49:28 +00001561 thr_q = map_threads_maybe_lookup( quit_tid );
1562 tl_assert(thr_q != NULL);
1563
1564 /* Complain if this thread holds any locks. */
1565 nHeld = HG_(cardinalityWS)( univ_lsets, thr_q->locksetA );
1566 tl_assert(nHeld >= 0);
1567 if (nHeld > 0) {
1568 HChar buf[80];
1569 VG_(sprintf)(buf, "Exiting thread still holds %d lock%s",
1570 nHeld, nHeld > 1 ? "s" : "");
sewardjf98e1c02008-10-25 16:22:41 +00001571 HG_(record_error_Misc)( thr_q, buf );
sewardjb4112022007-11-09 22:49:28 +00001572 }
1573
sewardj23f12002009-07-24 08:45:08 +00001574 /* Not much to do here:
1575 - tell libhb the thread is gone
1576 - clear the map_threads entry, in order that the Valgrind core
1577 can re-use it. */
sewardj61bc2c52011-02-09 10:34:00 +00001578 /* Cleanup actions (next 5 lines) copied in evh__atfork_child; keep
1579 in sync. */
sewardj23f12002009-07-24 08:45:08 +00001580 tl_assert(thr_q->hbthr);
1581 libhb_async_exit(thr_q->hbthr);
sewardjf98e1c02008-10-25 16:22:41 +00001582 tl_assert(thr_q->coretid == quit_tid);
1583 thr_q->coretid = VG_INVALID_THREADID;
sewardjb4112022007-11-09 22:49:28 +00001584 map_threads_delete( quit_tid );
1585
sewardjf98e1c02008-10-25 16:22:41 +00001586 if (HG_(clo_sanity_flags) & SCE_THREADS)
sewardjb4112022007-11-09 22:49:28 +00001587 all__sanity_check("evh__pre_thread_ll_exit-post");
1588}
1589
sewardj61bc2c52011-02-09 10:34:00 +00001590/* This is called immediately after fork, for the child only. 'tid'
1591 is the only surviving thread (as per POSIX rules on fork() in
1592 threaded programs), so we have to clean up map_threads to remove
1593 entries for any other threads. */
1594static
1595void evh__atfork_child ( ThreadId tid )
1596{
1597 UInt i;
1598 Thread* thr;
1599 /* Slot 0 should never be used. */
1600 thr = map_threads_maybe_lookup( 0/*INVALID*/ );
1601 tl_assert(!thr);
1602 /* Clean up all other slots except 'tid'. */
1603 for (i = 1; i < VG_N_THREADS; i++) {
1604 if (i == tid)
1605 continue;
1606 thr = map_threads_maybe_lookup(i);
1607 if (!thr)
1608 continue;
1609 /* Cleanup actions (next 5 lines) copied from end of
1610 evh__pre_thread_ll_exit; keep in sync. */
1611 tl_assert(thr->hbthr);
1612 libhb_async_exit(thr->hbthr);
1613 tl_assert(thr->coretid == i);
1614 thr->coretid = VG_INVALID_THREADID;
1615 map_threads_delete(i);
1616 }
1617}
1618
sewardjf98e1c02008-10-25 16:22:41 +00001619
sewardjb4112022007-11-09 22:49:28 +00001620static
1621void evh__HG_PTHREAD_JOIN_POST ( ThreadId stay_tid, Thread* quit_thr )
1622{
sewardjb4112022007-11-09 22:49:28 +00001623 Thread* thr_s;
1624 Thread* thr_q;
sewardjf98e1c02008-10-25 16:22:41 +00001625 Thr* hbthr_s;
1626 Thr* hbthr_q;
1627 SO* so;
sewardjb4112022007-11-09 22:49:28 +00001628
1629 if (SHOW_EVENTS >= 1)
1630 VG_(printf)("evh__post_thread_join(stayer=%d, quitter=%p)\n",
1631 (Int)stay_tid, quit_thr );
1632
sewardjf98e1c02008-10-25 16:22:41 +00001633 tl_assert(HG_(is_sane_ThreadId)(stay_tid));
sewardjb4112022007-11-09 22:49:28 +00001634
1635 thr_s = map_threads_maybe_lookup( stay_tid );
1636 thr_q = quit_thr;
1637 tl_assert(thr_s != NULL);
1638 tl_assert(thr_q != NULL);
1639 tl_assert(thr_s != thr_q);
1640
sewardjf98e1c02008-10-25 16:22:41 +00001641 hbthr_s = thr_s->hbthr;
1642 hbthr_q = thr_q->hbthr;
1643 tl_assert(hbthr_s != hbthr_q);
sewardj60626642011-03-10 15:14:37 +00001644 tl_assert( libhb_get_Thr_hgthread(hbthr_s) == thr_s );
1645 tl_assert( libhb_get_Thr_hgthread(hbthr_q) == thr_q );
sewardjb4112022007-11-09 22:49:28 +00001646
sewardjf98e1c02008-10-25 16:22:41 +00001647 /* Allocate a temporary synchronisation object and use it to send
1648 an imaginary message from the quitter to the stayer, the purpose
1649 being to generate a dependence from the quitter to the
1650 stayer. */
1651 so = libhb_so_alloc();
1652 tl_assert(so);
sewardj23f12002009-07-24 08:45:08 +00001653 /* Send last arg of _so_send as False, since the sending thread
1654 doesn't actually exist any more, so we don't want _so_send to
1655 try taking stack snapshots of it. */
sewardjf98e1c02008-10-25 16:22:41 +00001656 libhb_so_send(hbthr_q, so, True/*strong_send*/);
1657 libhb_so_recv(hbthr_s, so, True/*strong_recv*/);
1658 libhb_so_dealloc(so);
sewardjb4112022007-11-09 22:49:28 +00001659
sewardjf98e1c02008-10-25 16:22:41 +00001660 /* evh__pre_thread_ll_exit issues an error message if the exiting
1661 thread holds any locks. No need to check here. */
sewardjb4112022007-11-09 22:49:28 +00001662
1663 /* This holds because, at least when using NPTL as the thread
1664 library, we should be notified the low level thread exit before
1665 we hear of any join event on it. The low level exit
1666 notification feeds through into evh__pre_thread_ll_exit,
1667 which should clear the map_threads entry for it. Hence we
1668 expect there to be no map_threads entry at this point. */
1669 tl_assert( map_threads_maybe_reverse_lookup_SLOW(thr_q)
1670 == VG_INVALID_THREADID);
1671
sewardjf98e1c02008-10-25 16:22:41 +00001672 if (HG_(clo_sanity_flags) & SCE_THREADS)
sewardjb4112022007-11-09 22:49:28 +00001673 all__sanity_check("evh__post_thread_join-post");
1674}
1675
1676static
1677void evh__pre_mem_read ( CorePart part, ThreadId tid, Char* s,
1678 Addr a, SizeT size) {
1679 if (SHOW_EVENTS >= 2
1680 || (SHOW_EVENTS >= 1 && size != 1))
1681 VG_(printf)("evh__pre_mem_read(ctid=%d, \"%s\", %p, %lu)\n",
1682 (Int)tid, s, (void*)a, size );
sewardj23f12002009-07-24 08:45:08 +00001683 shadow_mem_cread_range( map_threads_lookup(tid), a, size);
sewardjf98e1c02008-10-25 16:22:41 +00001684 if (size >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
sewardjb4112022007-11-09 22:49:28 +00001685 all__sanity_check("evh__pre_mem_read-post");
1686}
1687
1688static
1689void evh__pre_mem_read_asciiz ( CorePart part, ThreadId tid,
1690 Char* s, Addr a ) {
1691 Int len;
1692 if (SHOW_EVENTS >= 1)
1693 VG_(printf)("evh__pre_mem_asciiz(ctid=%d, \"%s\", %p)\n",
1694 (Int)tid, s, (void*)a );
sewardj234e5582011-02-09 12:47:23 +00001695 // Don't segfault if the string starts in an obviously stupid
1696 // place. Actually we should check the whole string, not just
1697 // the start address, but that's too much trouble. At least
1698 // checking the first byte is better than nothing. See #255009.
1699 if (!VG_(am_is_valid_for_client) (a, 1, VKI_PROT_READ))
1700 return;
sewardjb4112022007-11-09 22:49:28 +00001701 len = VG_(strlen)( (Char*) a );
sewardj23f12002009-07-24 08:45:08 +00001702 shadow_mem_cread_range( map_threads_lookup(tid), a, len+1 );
sewardjf98e1c02008-10-25 16:22:41 +00001703 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
sewardjb4112022007-11-09 22:49:28 +00001704 all__sanity_check("evh__pre_mem_read_asciiz-post");
1705}
1706
1707static
1708void evh__pre_mem_write ( CorePart part, ThreadId tid, Char* s,
1709 Addr a, SizeT size ) {
1710 if (SHOW_EVENTS >= 1)
1711 VG_(printf)("evh__pre_mem_write(ctid=%d, \"%s\", %p, %lu)\n",
1712 (Int)tid, s, (void*)a, size );
sewardj23f12002009-07-24 08:45:08 +00001713 shadow_mem_cwrite_range( map_threads_lookup(tid), a, size);
sewardjf98e1c02008-10-25 16:22:41 +00001714 if (size >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
sewardjb4112022007-11-09 22:49:28 +00001715 all__sanity_check("evh__pre_mem_write-post");
1716}
1717
1718static
1719void evh__new_mem_heap ( Addr a, SizeT len, Bool is_inited ) {
1720 if (SHOW_EVENTS >= 1)
1721 VG_(printf)("evh__new_mem_heap(%p, %lu, inited=%d)\n",
1722 (void*)a, len, (Int)is_inited );
1723 // FIXME: this is kinda stupid
1724 if (is_inited) {
1725 shadow_mem_make_New(get_current_Thread(), a, len);
1726 } else {
1727 shadow_mem_make_New(get_current_Thread(), a, len);
1728 }
sewardjf98e1c02008-10-25 16:22:41 +00001729 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
sewardjb4112022007-11-09 22:49:28 +00001730 all__sanity_check("evh__pre_mem_read-post");
1731}
1732
1733static
1734void evh__die_mem_heap ( Addr a, SizeT len ) {
sewardj622fe492011-03-11 21:06:59 +00001735 Thread* thr;
sewardjb4112022007-11-09 22:49:28 +00001736 if (SHOW_EVENTS >= 1)
1737 VG_(printf)("evh__die_mem_heap(%p, %lu)\n", (void*)a, len );
sewardj622fe492011-03-11 21:06:59 +00001738 thr = get_current_Thread();
1739 tl_assert(thr);
1740 if (HG_(clo_free_is_write)) {
1741 /* Treat frees as if the memory was written immediately prior to
1742 the free. This shakes out more races, specifically, cases
1743 where memory is referenced by one thread, and freed by
1744 another, and there's no observable synchronisation event to
1745 guarantee that the reference happens before the free. */
1746 shadow_mem_cwrite_range(thr, a, len);
1747 }
sewardjfd35d492011-03-17 19:39:55 +00001748 shadow_mem_make_NoAccess_NoFX( thr, a, len );
sewardjf98e1c02008-10-25 16:22:41 +00001749 if (len >= SCE_BIGRANGE_T && (HG_(clo_sanity_flags) & SCE_BIGRANGE))
sewardjb4112022007-11-09 22:49:28 +00001750 all__sanity_check("evh__pre_mem_read-post");
1751}
1752
sewardj23f12002009-07-24 08:45:08 +00001753/* --- Event handlers called from generated code --- */
1754
sewardjb4112022007-11-09 22:49:28 +00001755static VG_REGPARM(1)
sewardj23f12002009-07-24 08:45:08 +00001756void evh__mem_help_cread_1(Addr a) {
sewardjf98e1c02008-10-25 16:22:41 +00001757 Thread* thr = get_current_Thread_in_C_C();
1758 Thr* hbthr = thr->hbthr;
sewardj23f12002009-07-24 08:45:08 +00001759 LIBHB_CREAD_1(hbthr, a);
sewardjb4112022007-11-09 22:49:28 +00001760}
sewardjf98e1c02008-10-25 16:22:41 +00001761
sewardjb4112022007-11-09 22:49:28 +00001762static VG_REGPARM(1)
sewardj23f12002009-07-24 08:45:08 +00001763void evh__mem_help_cread_2(Addr a) {
sewardjf98e1c02008-10-25 16:22:41 +00001764 Thread* thr = get_current_Thread_in_C_C();
1765 Thr* hbthr = thr->hbthr;
sewardj23f12002009-07-24 08:45:08 +00001766 LIBHB_CREAD_2(hbthr, a);
sewardjb4112022007-11-09 22:49:28 +00001767}
sewardjf98e1c02008-10-25 16:22:41 +00001768
sewardjb4112022007-11-09 22:49:28 +00001769static VG_REGPARM(1)
sewardj23f12002009-07-24 08:45:08 +00001770void evh__mem_help_cread_4(Addr a) {
sewardjf98e1c02008-10-25 16:22:41 +00001771 Thread* thr = get_current_Thread_in_C_C();
1772 Thr* hbthr = thr->hbthr;
sewardj23f12002009-07-24 08:45:08 +00001773 LIBHB_CREAD_4(hbthr, a);
sewardjb4112022007-11-09 22:49:28 +00001774}
sewardjf98e1c02008-10-25 16:22:41 +00001775
sewardjb4112022007-11-09 22:49:28 +00001776static VG_REGPARM(1)
sewardj23f12002009-07-24 08:45:08 +00001777void evh__mem_help_cread_8(Addr a) {
sewardjf98e1c02008-10-25 16:22:41 +00001778 Thread* thr = get_current_Thread_in_C_C();
1779 Thr* hbthr = thr->hbthr;
sewardj23f12002009-07-24 08:45:08 +00001780 LIBHB_CREAD_8(hbthr, a);
sewardjb4112022007-11-09 22:49:28 +00001781}
sewardjf98e1c02008-10-25 16:22:41 +00001782
sewardjb4112022007-11-09 22:49:28 +00001783static VG_REGPARM(2)
sewardj23f12002009-07-24 08:45:08 +00001784void evh__mem_help_cread_N(Addr a, SizeT size) {
sewardjf98e1c02008-10-25 16:22:41 +00001785 Thread* thr = get_current_Thread_in_C_C();
1786 Thr* hbthr = thr->hbthr;
sewardj23f12002009-07-24 08:45:08 +00001787 LIBHB_CREAD_N(hbthr, a, size);
sewardjb4112022007-11-09 22:49:28 +00001788}
1789
1790static VG_REGPARM(1)
sewardj23f12002009-07-24 08:45:08 +00001791void evh__mem_help_cwrite_1(Addr a) {
sewardjf98e1c02008-10-25 16:22:41 +00001792 Thread* thr = get_current_Thread_in_C_C();
1793 Thr* hbthr = thr->hbthr;
sewardj23f12002009-07-24 08:45:08 +00001794 LIBHB_CWRITE_1(hbthr, a);
sewardjb4112022007-11-09 22:49:28 +00001795}
sewardjf98e1c02008-10-25 16:22:41 +00001796
sewardjb4112022007-11-09 22:49:28 +00001797static VG_REGPARM(1)
sewardj23f12002009-07-24 08:45:08 +00001798void evh__mem_help_cwrite_2(Addr a) {
sewardjf98e1c02008-10-25 16:22:41 +00001799 Thread* thr = get_current_Thread_in_C_C();
1800 Thr* hbthr = thr->hbthr;
sewardj23f12002009-07-24 08:45:08 +00001801 LIBHB_CWRITE_2(hbthr, a);
sewardjb4112022007-11-09 22:49:28 +00001802}
sewardjf98e1c02008-10-25 16:22:41 +00001803
sewardjb4112022007-11-09 22:49:28 +00001804static VG_REGPARM(1)
sewardj23f12002009-07-24 08:45:08 +00001805void evh__mem_help_cwrite_4(Addr a) {
sewardjf98e1c02008-10-25 16:22:41 +00001806 Thread* thr = get_current_Thread_in_C_C();
1807 Thr* hbthr = thr->hbthr;
sewardj23f12002009-07-24 08:45:08 +00001808 LIBHB_CWRITE_4(hbthr, a);
sewardjb4112022007-11-09 22:49:28 +00001809}
sewardjf98e1c02008-10-25 16:22:41 +00001810
sewardjb4112022007-11-09 22:49:28 +00001811static VG_REGPARM(1)
sewardj23f12002009-07-24 08:45:08 +00001812void evh__mem_help_cwrite_8(Addr a) {
sewardjf98e1c02008-10-25 16:22:41 +00001813 Thread* thr = get_current_Thread_in_C_C();
1814 Thr* hbthr = thr->hbthr;
sewardj23f12002009-07-24 08:45:08 +00001815 LIBHB_CWRITE_8(hbthr, a);
sewardjb4112022007-11-09 22:49:28 +00001816}
sewardjf98e1c02008-10-25 16:22:41 +00001817
sewardjb4112022007-11-09 22:49:28 +00001818static VG_REGPARM(2)
sewardj23f12002009-07-24 08:45:08 +00001819void evh__mem_help_cwrite_N(Addr a, SizeT size) {
sewardjf98e1c02008-10-25 16:22:41 +00001820 Thread* thr = get_current_Thread_in_C_C();
1821 Thr* hbthr = thr->hbthr;
sewardj23f12002009-07-24 08:45:08 +00001822 LIBHB_CWRITE_N(hbthr, a, size);
sewardjb4112022007-11-09 22:49:28 +00001823}
1824
sewardjb4112022007-11-09 22:49:28 +00001825
sewardj9f569b72008-11-13 13:33:09 +00001826/* ------------------------------------------------------- */
sewardjb4112022007-11-09 22:49:28 +00001827/* -------------- events to do with mutexes -------------- */
sewardj9f569b72008-11-13 13:33:09 +00001828/* ------------------------------------------------------- */
sewardjb4112022007-11-09 22:49:28 +00001829
1830/* EXPOSITION only: by intercepting lock init events we can show the
1831 user where the lock was initialised, rather than only being able to
1832 show where it was first locked. Intercepting lock initialisations
1833 is not necessary for the basic operation of the race checker. */
1834static
1835void evh__HG_PTHREAD_MUTEX_INIT_POST( ThreadId tid,
1836 void* mutex, Word mbRec )
1837{
1838 if (SHOW_EVENTS >= 1)
1839 VG_(printf)("evh__hg_PTHREAD_MUTEX_INIT_POST(ctid=%d, mbRec=%ld, %p)\n",
1840 (Int)tid, mbRec, (void*)mutex );
1841 tl_assert(mbRec == 0 || mbRec == 1);
1842 map_locks_lookup_or_create( mbRec ? LK_mbRec : LK_nonRec,
1843 (Addr)mutex, tid );
sewardjf98e1c02008-10-25 16:22:41 +00001844 if (HG_(clo_sanity_flags) & SCE_LOCKS)
sewardjb4112022007-11-09 22:49:28 +00001845 all__sanity_check("evh__hg_PTHREAD_MUTEX_INIT_POST");
1846}
1847
1848static
1849void evh__HG_PTHREAD_MUTEX_DESTROY_PRE( ThreadId tid, void* mutex )
1850{
1851 Thread* thr;
1852 Lock* lk;
1853 if (SHOW_EVENTS >= 1)
1854 VG_(printf)("evh__hg_PTHREAD_MUTEX_DESTROY_PRE(ctid=%d, %p)\n",
1855 (Int)tid, (void*)mutex );
1856
1857 thr = map_threads_maybe_lookup( tid );
1858 /* cannot fail - Thread* must already exist */
sewardjf98e1c02008-10-25 16:22:41 +00001859 tl_assert( HG_(is_sane_Thread)(thr) );
sewardjb4112022007-11-09 22:49:28 +00001860
1861 lk = map_locks_maybe_lookup( (Addr)mutex );
1862
1863 if (lk == NULL || (lk->kind != LK_nonRec && lk->kind != LK_mbRec)) {
sewardjf98e1c02008-10-25 16:22:41 +00001864 HG_(record_error_Misc)(
1865 thr, "pthread_mutex_destroy with invalid argument" );
sewardjb4112022007-11-09 22:49:28 +00001866 }
1867
1868 if (lk) {
sewardjf98e1c02008-10-25 16:22:41 +00001869 tl_assert( HG_(is_sane_LockN)(lk) );
sewardjb4112022007-11-09 22:49:28 +00001870 tl_assert( lk->guestaddr == (Addr)mutex );
1871 if (lk->heldBy) {
1872 /* Basically act like we unlocked the lock */
sewardjf98e1c02008-10-25 16:22:41 +00001873 HG_(record_error_Misc)(
1874 thr, "pthread_mutex_destroy of a locked mutex" );
sewardjb4112022007-11-09 22:49:28 +00001875 /* remove lock from locksets of all owning threads */
1876 remove_Lock_from_locksets_of_all_owning_Threads( lk );
sewardj896f6f92008-08-19 08:38:52 +00001877 VG_(deleteBag)( lk->heldBy );
sewardjb4112022007-11-09 22:49:28 +00001878 lk->heldBy = NULL;
1879 lk->heldW = False;
1880 lk->acquired_at = NULL;
1881 }
1882 tl_assert( !lk->heldBy );
sewardjf98e1c02008-10-25 16:22:41 +00001883 tl_assert( HG_(is_sane_LockN)(lk) );
sewardjc1fb9d22011-02-28 09:03:44 +00001884
1885 if (HG_(clo_track_lockorders))
1886 laog__handle_one_lock_deletion(lk);
sewardjf98e1c02008-10-25 16:22:41 +00001887 map_locks_delete( lk->guestaddr );
1888 del_LockN( lk );
sewardjb4112022007-11-09 22:49:28 +00001889 }
1890
sewardjf98e1c02008-10-25 16:22:41 +00001891 if (HG_(clo_sanity_flags) & SCE_LOCKS)
sewardjb4112022007-11-09 22:49:28 +00001892 all__sanity_check("evh__hg_PTHREAD_MUTEX_DESTROY_PRE");
1893}
1894
1895static void evh__HG_PTHREAD_MUTEX_LOCK_PRE ( ThreadId tid,
1896 void* mutex, Word isTryLock )
1897{
1898 /* Just check the mutex is sane; nothing else to do. */
1899 // 'mutex' may be invalid - not checked by wrapper
1900 Thread* thr;
1901 Lock* lk;
1902 if (SHOW_EVENTS >= 1)
1903 VG_(printf)("evh__hg_PTHREAD_MUTEX_LOCK_PRE(ctid=%d, mutex=%p)\n",
1904 (Int)tid, (void*)mutex );
1905
1906 tl_assert(isTryLock == 0 || isTryLock == 1);
1907 thr = map_threads_maybe_lookup( tid );
1908 tl_assert(thr); /* cannot fail - Thread* must already exist */
1909
1910 lk = map_locks_maybe_lookup( (Addr)mutex );
1911
1912 if (lk && (lk->kind == LK_rdwr)) {
sewardjf98e1c02008-10-25 16:22:41 +00001913 HG_(record_error_Misc)( thr, "pthread_mutex_lock with a "
1914 "pthread_rwlock_t* argument " );
sewardjb4112022007-11-09 22:49:28 +00001915 }
1916
1917 if ( lk
1918 && isTryLock == 0
1919 && (lk->kind == LK_nonRec || lk->kind == LK_rdwr)
1920 && lk->heldBy
1921 && lk->heldW
sewardj896f6f92008-08-19 08:38:52 +00001922 && VG_(elemBag)( lk->heldBy, (Word)thr ) > 0 ) {
sewardjb4112022007-11-09 22:49:28 +00001923 /* uh, it's a non-recursive lock and we already w-hold it, and
1924 this is a real lock operation (not a speculative "tryLock"
1925 kind of thing). Duh. Deadlock coming up; but at least
1926 produce an error message. */
sewardj8fef6252010-07-29 05:28:02 +00001927 HChar* errstr = "Attempt to re-lock a "
1928 "non-recursive lock I already hold";
1929 HChar* auxstr = "Lock was previously acquired";
1930 if (lk->acquired_at) {
1931 HG_(record_error_Misc_w_aux)( thr, errstr, auxstr, lk->acquired_at );
1932 } else {
1933 HG_(record_error_Misc)( thr, errstr );
1934 }
sewardjb4112022007-11-09 22:49:28 +00001935 }
1936}
1937
1938static void evh__HG_PTHREAD_MUTEX_LOCK_POST ( ThreadId tid, void* mutex )
1939{
1940 // only called if the real library call succeeded - so mutex is sane
1941 Thread* thr;
1942 if (SHOW_EVENTS >= 1)
1943 VG_(printf)("evh__HG_PTHREAD_MUTEX_LOCK_POST(ctid=%d, mutex=%p)\n",
1944 (Int)tid, (void*)mutex );
1945
1946 thr = map_threads_maybe_lookup( tid );
1947 tl_assert(thr); /* cannot fail - Thread* must already exist */
1948
1949 evhH__post_thread_w_acquires_lock(
1950 thr,
1951 LK_mbRec, /* if not known, create new lock with this LockKind */
1952 (Addr)mutex
1953 );
1954}
1955
1956static void evh__HG_PTHREAD_MUTEX_UNLOCK_PRE ( ThreadId tid, void* mutex )
1957{
1958 // 'mutex' may be invalid - not checked by wrapper
1959 Thread* thr;
1960 if (SHOW_EVENTS >= 1)
1961 VG_(printf)("evh__HG_PTHREAD_MUTEX_UNLOCK_PRE(ctid=%d, mutex=%p)\n",
1962 (Int)tid, (void*)mutex );
1963
1964 thr = map_threads_maybe_lookup( tid );
1965 tl_assert(thr); /* cannot fail - Thread* must already exist */
1966
1967 evhH__pre_thread_releases_lock( thr, (Addr)mutex, False/*!isRDWR*/ );
1968}
1969
1970static void evh__HG_PTHREAD_MUTEX_UNLOCK_POST ( ThreadId tid, void* mutex )
1971{
1972 // only called if the real library call succeeded - so mutex is sane
1973 Thread* thr;
1974 if (SHOW_EVENTS >= 1)
1975 VG_(printf)("evh__hg_PTHREAD_MUTEX_UNLOCK_POST(ctid=%d, mutex=%p)\n",
1976 (Int)tid, (void*)mutex );
1977 thr = map_threads_maybe_lookup( tid );
1978 tl_assert(thr); /* cannot fail - Thread* must already exist */
1979
1980 // anything we should do here?
1981}
1982
1983
sewardj5a644da2009-08-11 10:35:58 +00001984/* ------------------------------------------------------- */
sewardj1f77fec2010-04-12 19:51:04 +00001985/* -------------- events to do with spinlocks ------------ */
sewardj5a644da2009-08-11 10:35:58 +00001986/* ------------------------------------------------------- */
1987
1988/* All a bit of a kludge. Pretend we're really dealing with ordinary
1989 pthread_mutex_t's instead, for the most part. */
1990
1991static void evh__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE( ThreadId tid,
1992 void* slock )
1993{
1994 Thread* thr;
1995 Lock* lk;
1996 /* In glibc's kludgey world, we're either initialising or unlocking
1997 it. Since this is the pre-routine, if it is locked, unlock it
1998 and take a dependence edge. Otherwise, do nothing. */
1999
2000 if (SHOW_EVENTS >= 1)
2001 VG_(printf)("evh__hg_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE"
2002 "(ctid=%d, slock=%p)\n",
2003 (Int)tid, (void*)slock );
2004
2005 thr = map_threads_maybe_lookup( tid );
2006 /* cannot fail - Thread* must already exist */;
2007 tl_assert( HG_(is_sane_Thread)(thr) );
2008
2009 lk = map_locks_maybe_lookup( (Addr)slock );
2010 if (lk && lk->heldBy) {
2011 /* it's held. So do the normal pre-unlock actions, as copied
2012 from evh__HG_PTHREAD_MUTEX_UNLOCK_PRE. This stupidly
2013 duplicates the map_locks_maybe_lookup. */
2014 evhH__pre_thread_releases_lock( thr, (Addr)slock,
2015 False/*!isRDWR*/ );
2016 }
2017}
2018
2019static void evh__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST( ThreadId tid,
2020 void* slock )
2021{
2022 Lock* lk;
2023 /* More kludgery. If the lock has never been seen before, do
2024 actions as per evh__HG_PTHREAD_MUTEX_INIT_POST. Else do
2025 nothing. */
2026
2027 if (SHOW_EVENTS >= 1)
2028 VG_(printf)("evh__hg_PTHREAD_SPIN_INIT_OR_UNLOCK_POST"
2029 "(ctid=%d, slock=%p)\n",
2030 (Int)tid, (void*)slock );
2031
2032 lk = map_locks_maybe_lookup( (Addr)slock );
2033 if (!lk) {
2034 map_locks_lookup_or_create( LK_nonRec, (Addr)slock, tid );
2035 }
2036}
2037
2038static void evh__HG_PTHREAD_SPIN_LOCK_PRE( ThreadId tid,
2039 void* slock, Word isTryLock )
2040{
2041 evh__HG_PTHREAD_MUTEX_LOCK_PRE( tid, slock, isTryLock );
2042}
2043
2044static void evh__HG_PTHREAD_SPIN_LOCK_POST( ThreadId tid,
2045 void* slock )
2046{
2047 evh__HG_PTHREAD_MUTEX_LOCK_POST( tid, slock );
2048}
2049
2050static void evh__HG_PTHREAD_SPIN_DESTROY_PRE( ThreadId tid,
2051 void* slock )
2052{
2053 evh__HG_PTHREAD_MUTEX_DESTROY_PRE( tid, slock );
2054}
2055
2056
sewardj9f569b72008-11-13 13:33:09 +00002057/* ----------------------------------------------------- */
sewardjb4112022007-11-09 22:49:28 +00002058/* --------------- events to do with CVs --------------- */
sewardj9f569b72008-11-13 13:33:09 +00002059/* ----------------------------------------------------- */
sewardjb4112022007-11-09 22:49:28 +00002060
sewardj02114542009-07-28 20:52:36 +00002061/* A mapping from CV to (the SO associated with it, plus some
2062 auxiliary data for error checking). When the CV is
sewardjf98e1c02008-10-25 16:22:41 +00002063 signalled/broadcasted upon, we do a 'send' into the SO, and when a
2064 wait on it completes, we do a 'recv' from the SO. This is believed
2065 to give the correct happens-before events arising from CV
sewardjb4112022007-11-09 22:49:28 +00002066 signallings/broadcasts.
2067*/
2068
sewardj02114542009-07-28 20:52:36 +00002069/* .so is the SO for this CV.
2070 .mx_ga is the associated mutex, when .nWaiters > 0
sewardjb4112022007-11-09 22:49:28 +00002071
sewardj02114542009-07-28 20:52:36 +00002072 POSIX says effectively that the first pthread_cond_{timed}wait call
2073 causes a dynamic binding between the CV and the mutex, and that
2074 lasts until such time as the waiter count falls to zero. Hence
2075 need to keep track of the number of waiters in order to do
2076 consistency tracking. */
2077typedef
2078 struct {
2079 SO* so; /* libhb-allocated SO */
2080 void* mx_ga; /* addr of associated mutex, if any */
2081 UWord nWaiters; /* # threads waiting on the CV */
2082 }
2083 CVInfo;
2084
2085
2086/* pthread_cond_t* -> CVInfo* */
2087static WordFM* map_cond_to_CVInfo = NULL;
2088
2089static void map_cond_to_CVInfo_INIT ( void ) {
2090 if (UNLIKELY(map_cond_to_CVInfo == NULL)) {
2091 map_cond_to_CVInfo = VG_(newFM)( HG_(zalloc),
2092 "hg.mctCI.1", HG_(free), NULL );
2093 tl_assert(map_cond_to_CVInfo != NULL);
sewardjf98e1c02008-10-25 16:22:41 +00002094 }
2095}
2096
sewardj02114542009-07-28 20:52:36 +00002097static CVInfo* map_cond_to_CVInfo_lookup_or_alloc ( void* cond ) {
sewardjf98e1c02008-10-25 16:22:41 +00002098 UWord key, val;
sewardj02114542009-07-28 20:52:36 +00002099 map_cond_to_CVInfo_INIT();
2100 if (VG_(lookupFM)( map_cond_to_CVInfo, &key, &val, (UWord)cond )) {
sewardjf98e1c02008-10-25 16:22:41 +00002101 tl_assert(key == (UWord)cond);
sewardj02114542009-07-28 20:52:36 +00002102 return (CVInfo*)val;
sewardjf98e1c02008-10-25 16:22:41 +00002103 } else {
sewardj02114542009-07-28 20:52:36 +00002104 SO* so = libhb_so_alloc();
2105 CVInfo* cvi = HG_(zalloc)("hg.mctCloa.1", sizeof(CVInfo));
2106 cvi->so = so;
2107 cvi->mx_ga = 0;
2108 VG_(addToFM)( map_cond_to_CVInfo, (UWord)cond, (UWord)cvi );
2109 return cvi;
sewardjf98e1c02008-10-25 16:22:41 +00002110 }
2111}
2112
sewardj02114542009-07-28 20:52:36 +00002113static void map_cond_to_CVInfo_delete ( void* cond ) {
sewardjf98e1c02008-10-25 16:22:41 +00002114 UWord keyW, valW;
sewardj02114542009-07-28 20:52:36 +00002115 map_cond_to_CVInfo_INIT();
2116 if (VG_(delFromFM)( map_cond_to_CVInfo, &keyW, &valW, (UWord)cond )) {
2117 CVInfo* cvi = (CVInfo*)valW;
sewardjf98e1c02008-10-25 16:22:41 +00002118 tl_assert(keyW == (UWord)cond);
sewardj02114542009-07-28 20:52:36 +00002119 tl_assert(cvi);
2120 tl_assert(cvi->so);
2121 libhb_so_dealloc(cvi->so);
2122 cvi->mx_ga = 0;
2123 HG_(free)(cvi);
sewardjb4112022007-11-09 22:49:28 +00002124 }
2125}
2126
2127static void evh__HG_PTHREAD_COND_SIGNAL_PRE ( ThreadId tid, void* cond )
2128{
sewardjf98e1c02008-10-25 16:22:41 +00002129 /* 'tid' has signalled on 'cond'. As per the comment above, bind
2130 cond to a SO if it is not already so bound, and 'send' on the
2131 SO. This is later used by other thread(s) which successfully
2132 exit from a pthread_cond_wait on the same cv; then they 'recv'
2133 from the SO, thereby acquiring a dependency on this signalling
2134 event. */
sewardjb4112022007-11-09 22:49:28 +00002135 Thread* thr;
sewardj02114542009-07-28 20:52:36 +00002136 CVInfo* cvi;
2137 //Lock* lk;
sewardjb4112022007-11-09 22:49:28 +00002138
2139 if (SHOW_EVENTS >= 1)
2140 VG_(printf)("evh__HG_PTHREAD_COND_SIGNAL_PRE(ctid=%d, cond=%p)\n",
2141 (Int)tid, (void*)cond );
2142
sewardjb4112022007-11-09 22:49:28 +00002143 thr = map_threads_maybe_lookup( tid );
2144 tl_assert(thr); /* cannot fail - Thread* must already exist */
2145
sewardj02114542009-07-28 20:52:36 +00002146 cvi = map_cond_to_CVInfo_lookup_or_alloc( cond );
2147 tl_assert(cvi);
2148 tl_assert(cvi->so);
2149
sewardjb4112022007-11-09 22:49:28 +00002150 // error-if: mutex is bogus
2151 // error-if: mutex is not locked
sewardj02114542009-07-28 20:52:36 +00002152 // Hmm. POSIX doesn't actually say that it's an error to call
2153 // pthread_cond_signal with the associated mutex being unlocked.
2154 // Although it does say that it should be "if consistent scheduling
2155 // is desired."
2156 //
2157 // For the moment, disable these checks.
2158 //lk = map_locks_maybe_lookup(cvi->mx_ga);
2159 //if (lk == NULL || cvi->mx_ga == 0) {
2160 // HG_(record_error_Misc)( thr,
2161 // "pthread_cond_{signal,broadcast}: "
2162 // "no or invalid mutex associated with cond");
2163 //}
2164 ///* note: lk could be NULL. Be careful. */
2165 //if (lk) {
2166 // if (lk->kind == LK_rdwr) {
2167 // HG_(record_error_Misc)(thr,
2168 // "pthread_cond_{signal,broadcast}: associated lock is a rwlock");
2169 // }
2170 // if (lk->heldBy == NULL) {
2171 // HG_(record_error_Misc)(thr,
2172 // "pthread_cond_{signal,broadcast}: "
2173 // "associated lock is not held by any thread");
2174 // }
2175 // if (lk->heldBy != NULL && 0 == VG_(elemBag)(lk->heldBy, (Word)thr)) {
2176 // HG_(record_error_Misc)(thr,
2177 // "pthread_cond_{signal,broadcast}: "
2178 // "associated lock is not held by calling thread");
2179 // }
2180 //}
sewardjb4112022007-11-09 22:49:28 +00002181
sewardj02114542009-07-28 20:52:36 +00002182 libhb_so_send( thr->hbthr, cvi->so, True/*strong_send*/ );
sewardjb4112022007-11-09 22:49:28 +00002183}
2184
2185/* returns True if it reckons 'mutex' is valid and held by this
2186 thread, else False */
2187static Bool evh__HG_PTHREAD_COND_WAIT_PRE ( ThreadId tid,
2188 void* cond, void* mutex )
2189{
2190 Thread* thr;
2191 Lock* lk;
2192 Bool lk_valid = True;
sewardj02114542009-07-28 20:52:36 +00002193 CVInfo* cvi;
sewardjb4112022007-11-09 22:49:28 +00002194
2195 if (SHOW_EVENTS >= 1)
2196 VG_(printf)("evh__hg_PTHREAD_COND_WAIT_PRE"
2197 "(ctid=%d, cond=%p, mutex=%p)\n",
2198 (Int)tid, (void*)cond, (void*)mutex );
2199
sewardjb4112022007-11-09 22:49:28 +00002200 thr = map_threads_maybe_lookup( tid );
2201 tl_assert(thr); /* cannot fail - Thread* must already exist */
2202
2203 lk = map_locks_maybe_lookup( (Addr)mutex );
2204
2205 /* Check for stupid mutex arguments. There are various ways to be
2206 a bozo. Only complain once, though, even if more than one thing
2207 is wrong. */
2208 if (lk == NULL) {
2209 lk_valid = False;
sewardjf98e1c02008-10-25 16:22:41 +00002210 HG_(record_error_Misc)(
sewardjb4112022007-11-09 22:49:28 +00002211 thr,
2212 "pthread_cond_{timed}wait called with invalid mutex" );
2213 } else {
sewardjf98e1c02008-10-25 16:22:41 +00002214 tl_assert( HG_(is_sane_LockN)(lk) );
sewardjb4112022007-11-09 22:49:28 +00002215 if (lk->kind == LK_rdwr) {
2216 lk_valid = False;
sewardjf98e1c02008-10-25 16:22:41 +00002217 HG_(record_error_Misc)(
sewardjb4112022007-11-09 22:49:28 +00002218 thr, "pthread_cond_{timed}wait called with mutex "
2219 "of type pthread_rwlock_t*" );
2220 } else
2221 if (lk->heldBy == NULL) {
2222 lk_valid = False;
sewardjf98e1c02008-10-25 16:22:41 +00002223 HG_(record_error_Misc)(
sewardjb4112022007-11-09 22:49:28 +00002224 thr, "pthread_cond_{timed}wait called with un-held mutex");
2225 } else
2226 if (lk->heldBy != NULL
sewardj896f6f92008-08-19 08:38:52 +00002227 && VG_(elemBag)( lk->heldBy, (Word)thr ) == 0) {
sewardjb4112022007-11-09 22:49:28 +00002228 lk_valid = False;
sewardjf98e1c02008-10-25 16:22:41 +00002229 HG_(record_error_Misc)(
sewardjb4112022007-11-09 22:49:28 +00002230 thr, "pthread_cond_{timed}wait called with mutex "
2231 "held by a different thread" );
2232 }
2233 }
2234
2235 // error-if: cond is also associated with a different mutex
sewardj02114542009-07-28 20:52:36 +00002236 cvi = map_cond_to_CVInfo_lookup_or_alloc(cond);
2237 tl_assert(cvi);
2238 tl_assert(cvi->so);
2239 if (cvi->nWaiters == 0) {
2240 /* form initial (CV,MX) binding */
2241 cvi->mx_ga = mutex;
2242 }
2243 else /* check existing (CV,MX) binding */
2244 if (cvi->mx_ga != mutex) {
2245 HG_(record_error_Misc)(
2246 thr, "pthread_cond_{timed}wait: cond is associated "
2247 "with a different mutex");
2248 }
2249 cvi->nWaiters++;
sewardjb4112022007-11-09 22:49:28 +00002250
2251 return lk_valid;
2252}
2253
2254static void evh__HG_PTHREAD_COND_WAIT_POST ( ThreadId tid,
2255 void* cond, void* mutex )
2256{
sewardjf98e1c02008-10-25 16:22:41 +00002257 /* A pthread_cond_wait(cond, mutex) completed successfully. Find
2258 the SO for this cond, and 'recv' from it so as to acquire a
2259 dependency edge back to the signaller/broadcaster. */
2260 Thread* thr;
sewardj02114542009-07-28 20:52:36 +00002261 CVInfo* cvi;
sewardjb4112022007-11-09 22:49:28 +00002262
2263 if (SHOW_EVENTS >= 1)
2264 VG_(printf)("evh__HG_PTHREAD_COND_WAIT_POST"
2265 "(ctid=%d, cond=%p, mutex=%p)\n",
2266 (Int)tid, (void*)cond, (void*)mutex );
2267
sewardjb4112022007-11-09 22:49:28 +00002268 thr = map_threads_maybe_lookup( tid );
2269 tl_assert(thr); /* cannot fail - Thread* must already exist */
2270
2271 // error-if: cond is also associated with a different mutex
2272
sewardj02114542009-07-28 20:52:36 +00002273 cvi = map_cond_to_CVInfo_lookup_or_alloc( cond );
2274 tl_assert(cvi);
2275 tl_assert(cvi->so);
2276 tl_assert(cvi->nWaiters > 0);
sewardjb4112022007-11-09 22:49:28 +00002277
sewardj02114542009-07-28 20:52:36 +00002278 if (!libhb_so_everSent(cvi->so)) {
sewardjf98e1c02008-10-25 16:22:41 +00002279 /* Hmm. How can a wait on 'cond' succeed if nobody signalled
2280 it? If this happened it would surely be a bug in the threads
2281 library. Or one of those fabled "spurious wakeups". */
2282 HG_(record_error_Misc)( thr, "Bug in libpthread: pthread_cond_wait "
2283 "succeeded on"
2284 " without prior pthread_cond_post");
sewardjb4112022007-11-09 22:49:28 +00002285 }
sewardjf98e1c02008-10-25 16:22:41 +00002286
2287 /* anyway, acquire a dependency on it. */
sewardj02114542009-07-28 20:52:36 +00002288 libhb_so_recv( thr->hbthr, cvi->so, True/*strong_recv*/ );
2289
2290 cvi->nWaiters--;
sewardjf98e1c02008-10-25 16:22:41 +00002291}
2292
2293static void evh__HG_PTHREAD_COND_DESTROY_PRE ( ThreadId tid,
2294 void* cond )
2295{
2296 /* Deal with destroy events. The only purpose is to free storage
2297 associated with the CV, so as to avoid any possible resource
2298 leaks. */
2299 if (SHOW_EVENTS >= 1)
2300 VG_(printf)("evh__HG_PTHREAD_COND_DESTROY_PRE"
2301 "(ctid=%d, cond=%p)\n",
2302 (Int)tid, (void*)cond );
2303
sewardj02114542009-07-28 20:52:36 +00002304 map_cond_to_CVInfo_delete( cond );
sewardjb4112022007-11-09 22:49:28 +00002305}
2306
2307
sewardj9f569b72008-11-13 13:33:09 +00002308/* ------------------------------------------------------- */
sewardjb4112022007-11-09 22:49:28 +00002309/* -------------- events to do with rwlocks -------------- */
sewardj9f569b72008-11-13 13:33:09 +00002310/* ------------------------------------------------------- */
sewardjb4112022007-11-09 22:49:28 +00002311
2312/* EXPOSITION only */
2313static
2314void evh__HG_PTHREAD_RWLOCK_INIT_POST( ThreadId tid, void* rwl )
2315{
2316 if (SHOW_EVENTS >= 1)
2317 VG_(printf)("evh__hg_PTHREAD_RWLOCK_INIT_POST(ctid=%d, %p)\n",
2318 (Int)tid, (void*)rwl );
2319 map_locks_lookup_or_create( LK_rdwr, (Addr)rwl, tid );
sewardjf98e1c02008-10-25 16:22:41 +00002320 if (HG_(clo_sanity_flags) & SCE_LOCKS)
sewardjb4112022007-11-09 22:49:28 +00002321 all__sanity_check("evh__hg_PTHREAD_RWLOCK_INIT_POST");
2322}
2323
2324static
2325void evh__HG_PTHREAD_RWLOCK_DESTROY_PRE( ThreadId tid, void* rwl )
2326{
2327 Thread* thr;
2328 Lock* lk;
2329 if (SHOW_EVENTS >= 1)
2330 VG_(printf)("evh__hg_PTHREAD_RWLOCK_DESTROY_PRE(ctid=%d, %p)\n",
2331 (Int)tid, (void*)rwl );
2332
2333 thr = map_threads_maybe_lookup( tid );
2334 /* cannot fail - Thread* must already exist */
sewardjf98e1c02008-10-25 16:22:41 +00002335 tl_assert( HG_(is_sane_Thread)(thr) );
sewardjb4112022007-11-09 22:49:28 +00002336
2337 lk = map_locks_maybe_lookup( (Addr)rwl );
2338
2339 if (lk == NULL || lk->kind != LK_rdwr) {
sewardjf98e1c02008-10-25 16:22:41 +00002340 HG_(record_error_Misc)(
2341 thr, "pthread_rwlock_destroy with invalid argument" );
sewardjb4112022007-11-09 22:49:28 +00002342 }
2343
2344 if (lk) {
sewardjf98e1c02008-10-25 16:22:41 +00002345 tl_assert( HG_(is_sane_LockN)(lk) );
sewardjb4112022007-11-09 22:49:28 +00002346 tl_assert( lk->guestaddr == (Addr)rwl );
2347 if (lk->heldBy) {
2348 /* Basically act like we unlocked the lock */
sewardjf98e1c02008-10-25 16:22:41 +00002349 HG_(record_error_Misc)(
2350 thr, "pthread_rwlock_destroy of a locked mutex" );
sewardjb4112022007-11-09 22:49:28 +00002351 /* remove lock from locksets of all owning threads */
2352 remove_Lock_from_locksets_of_all_owning_Threads( lk );
sewardj896f6f92008-08-19 08:38:52 +00002353 VG_(deleteBag)( lk->heldBy );
sewardjb4112022007-11-09 22:49:28 +00002354 lk->heldBy = NULL;
2355 lk->heldW = False;
sewardj1c7e8332007-11-29 13:04:03 +00002356 lk->acquired_at = NULL;
sewardjb4112022007-11-09 22:49:28 +00002357 }
2358 tl_assert( !lk->heldBy );
sewardjf98e1c02008-10-25 16:22:41 +00002359 tl_assert( HG_(is_sane_LockN)(lk) );
sewardjc1fb9d22011-02-28 09:03:44 +00002360
2361 if (HG_(clo_track_lockorders))
2362 laog__handle_one_lock_deletion(lk);
sewardjf98e1c02008-10-25 16:22:41 +00002363 map_locks_delete( lk->guestaddr );
2364 del_LockN( lk );
sewardjb4112022007-11-09 22:49:28 +00002365 }
2366
sewardjf98e1c02008-10-25 16:22:41 +00002367 if (HG_(clo_sanity_flags) & SCE_LOCKS)
sewardjb4112022007-11-09 22:49:28 +00002368 all__sanity_check("evh__hg_PTHREAD_RWLOCK_DESTROY_PRE");
2369}
2370
2371static
sewardj789c3c52008-02-25 12:10:07 +00002372void evh__HG_PTHREAD_RWLOCK_LOCK_PRE ( ThreadId tid,
2373 void* rwl,
2374 Word isW, Word isTryLock )
sewardjb4112022007-11-09 22:49:28 +00002375{
2376 /* Just check the rwl is sane; nothing else to do. */
2377 // 'rwl' may be invalid - not checked by wrapper
2378 Thread* thr;
2379 Lock* lk;
2380 if (SHOW_EVENTS >= 1)
2381 VG_(printf)("evh__hg_PTHREAD_RWLOCK_LOCK_PRE(ctid=%d, isW=%d, %p)\n",
2382 (Int)tid, (Int)isW, (void*)rwl );
2383
2384 tl_assert(isW == 0 || isW == 1); /* assured us by wrapper */
sewardj789c3c52008-02-25 12:10:07 +00002385 tl_assert(isTryLock == 0 || isTryLock == 1); /* assured us by wrapper */
sewardjb4112022007-11-09 22:49:28 +00002386 thr = map_threads_maybe_lookup( tid );
2387 tl_assert(thr); /* cannot fail - Thread* must already exist */
2388
2389 lk = map_locks_maybe_lookup( (Addr)rwl );
2390 if ( lk
2391 && (lk->kind == LK_nonRec || lk->kind == LK_mbRec) ) {
2392 /* Wrong kind of lock. Duh. */
sewardjf98e1c02008-10-25 16:22:41 +00002393 HG_(record_error_Misc)(
2394 thr, "pthread_rwlock_{rd,rw}lock with a "
2395 "pthread_mutex_t* argument " );
sewardjb4112022007-11-09 22:49:28 +00002396 }
2397}
2398
2399static
2400void evh__HG_PTHREAD_RWLOCK_LOCK_POST ( ThreadId tid, void* rwl, Word isW )
2401{
2402 // only called if the real library call succeeded - so mutex is sane
2403 Thread* thr;
2404 if (SHOW_EVENTS >= 1)
2405 VG_(printf)("evh__hg_PTHREAD_RWLOCK_LOCK_POST(ctid=%d, isW=%d, %p)\n",
2406 (Int)tid, (Int)isW, (void*)rwl );
2407
2408 tl_assert(isW == 0 || isW == 1); /* assured us by wrapper */
2409 thr = map_threads_maybe_lookup( tid );
2410 tl_assert(thr); /* cannot fail - Thread* must already exist */
2411
2412 (isW ? evhH__post_thread_w_acquires_lock
2413 : evhH__post_thread_r_acquires_lock)(
2414 thr,
2415 LK_rdwr, /* if not known, create new lock with this LockKind */
2416 (Addr)rwl
2417 );
2418}
2419
2420static void evh__HG_PTHREAD_RWLOCK_UNLOCK_PRE ( ThreadId tid, void* rwl )
2421{
2422 // 'rwl' may be invalid - not checked by wrapper
2423 Thread* thr;
2424 if (SHOW_EVENTS >= 1)
2425 VG_(printf)("evh__HG_PTHREAD_RWLOCK_UNLOCK_PRE(ctid=%d, rwl=%p)\n",
2426 (Int)tid, (void*)rwl );
2427
2428 thr = map_threads_maybe_lookup( tid );
2429 tl_assert(thr); /* cannot fail - Thread* must already exist */
2430
2431 evhH__pre_thread_releases_lock( thr, (Addr)rwl, True/*isRDWR*/ );
2432}
2433
2434static void evh__HG_PTHREAD_RWLOCK_UNLOCK_POST ( ThreadId tid, void* rwl )
2435{
2436 // only called if the real library call succeeded - so mutex is sane
2437 Thread* thr;
2438 if (SHOW_EVENTS >= 1)
2439 VG_(printf)("evh__hg_PTHREAD_RWLOCK_UNLOCK_POST(ctid=%d, rwl=%p)\n",
2440 (Int)tid, (void*)rwl );
2441 thr = map_threads_maybe_lookup( tid );
2442 tl_assert(thr); /* cannot fail - Thread* must already exist */
2443
2444 // anything we should do here?
2445}
2446
2447
sewardj9f569b72008-11-13 13:33:09 +00002448/* ---------------------------------------------------------- */
2449/* -------------- events to do with semaphores -------------- */
2450/* ---------------------------------------------------------- */
sewardjb4112022007-11-09 22:49:28 +00002451
sewardj11e352f2007-11-30 11:11:02 +00002452/* This is similar to but not identical to the handling for condition
sewardjb4112022007-11-09 22:49:28 +00002453 variables. */
2454
sewardjf98e1c02008-10-25 16:22:41 +00002455/* For each semaphore, we maintain a stack of SOs. When a 'post'
2456 operation is done on a semaphore (unlocking, essentially), a new SO
2457 is created for the posting thread, the posting thread does a strong
2458 send to it (which merely installs the posting thread's VC in the
2459 SO), and the SO is pushed on the semaphore's stack.
sewardjb4112022007-11-09 22:49:28 +00002460
2461 Later, when a (probably different) thread completes 'wait' on the
sewardjf98e1c02008-10-25 16:22:41 +00002462 semaphore, we pop a SO off the semaphore's stack (which should be
2463 nonempty), and do a strong recv from it. This mechanism creates
sewardjb4112022007-11-09 22:49:28 +00002464 dependencies between posters and waiters of the semaphore.
2465
sewardjf98e1c02008-10-25 16:22:41 +00002466 It may not be necessary to use a stack - perhaps a bag of SOs would
2467 do. But we do need to keep track of how many unused-up posts have
2468 happened for the semaphore.
sewardjb4112022007-11-09 22:49:28 +00002469
sewardjf98e1c02008-10-25 16:22:41 +00002470 Imagine T1 and T2 both post once on a semaphore S, and T3 waits
sewardjb4112022007-11-09 22:49:28 +00002471 twice on S. T3 cannot complete its waits without both T1 and T2
2472 posting. The above mechanism will ensure that T3 acquires
2473 dependencies on both T1 and T2.
sewardj11e352f2007-11-30 11:11:02 +00002474
sewardjf98e1c02008-10-25 16:22:41 +00002475 When a semaphore is initialised with value N, we do as if we'd
2476 posted N times on the semaphore: basically create N SOs and do a
2477 strong send to all of then. This allows up to N waits on the
2478 semaphore to acquire a dependency on the initialisation point,
2479 which AFAICS is the correct behaviour.
sewardj11e352f2007-11-30 11:11:02 +00002480
2481 We don't emit an error for DESTROY_PRE on a semaphore we don't know
2482 about. We should.
sewardjb4112022007-11-09 22:49:28 +00002483*/
2484
sewardjf98e1c02008-10-25 16:22:41 +00002485/* sem_t* -> XArray* SO* */
2486static WordFM* map_sem_to_SO_stack = NULL;
sewardjb4112022007-11-09 22:49:28 +00002487
sewardjf98e1c02008-10-25 16:22:41 +00002488static void map_sem_to_SO_stack_INIT ( void ) {
2489 if (map_sem_to_SO_stack == NULL) {
2490 map_sem_to_SO_stack = VG_(newFM)( HG_(zalloc), "hg.mstSs.1",
2491 HG_(free), NULL );
2492 tl_assert(map_sem_to_SO_stack != NULL);
sewardjb4112022007-11-09 22:49:28 +00002493 }
2494}
2495
sewardjf98e1c02008-10-25 16:22:41 +00002496static void push_SO_for_sem ( void* sem, SO* so ) {
2497 UWord keyW;
sewardjb4112022007-11-09 22:49:28 +00002498 XArray* xa;
sewardjf98e1c02008-10-25 16:22:41 +00002499 tl_assert(so);
2500 map_sem_to_SO_stack_INIT();
2501 if (VG_(lookupFM)( map_sem_to_SO_stack,
2502 &keyW, (UWord*)&xa, (UWord)sem )) {
2503 tl_assert(keyW == (UWord)sem);
sewardjb4112022007-11-09 22:49:28 +00002504 tl_assert(xa);
sewardjf98e1c02008-10-25 16:22:41 +00002505 VG_(addToXA)( xa, &so );
sewardjb4112022007-11-09 22:49:28 +00002506 } else {
sewardjf98e1c02008-10-25 16:22:41 +00002507 xa = VG_(newXA)( HG_(zalloc), "hg.pSfs.1", HG_(free), sizeof(SO*) );
2508 VG_(addToXA)( xa, &so );
2509 VG_(addToFM)( map_sem_to_SO_stack, (Word)sem, (Word)xa );
sewardjb4112022007-11-09 22:49:28 +00002510 }
2511}
2512
sewardjf98e1c02008-10-25 16:22:41 +00002513static SO* mb_pop_SO_for_sem ( void* sem ) {
2514 UWord keyW;
sewardjb4112022007-11-09 22:49:28 +00002515 XArray* xa;
sewardjf98e1c02008-10-25 16:22:41 +00002516 SO* so;
2517 map_sem_to_SO_stack_INIT();
2518 if (VG_(lookupFM)( map_sem_to_SO_stack,
2519 &keyW, (UWord*)&xa, (UWord)sem )) {
sewardjb4112022007-11-09 22:49:28 +00002520 /* xa is the stack for this semaphore. */
sewardjf98e1c02008-10-25 16:22:41 +00002521 Word sz;
2522 tl_assert(keyW == (UWord)sem);
2523 sz = VG_(sizeXA)( xa );
sewardjb4112022007-11-09 22:49:28 +00002524 tl_assert(sz >= 0);
2525 if (sz == 0)
2526 return NULL; /* odd, the stack is empty */
sewardjf98e1c02008-10-25 16:22:41 +00002527 so = *(SO**)VG_(indexXA)( xa, sz-1 );
2528 tl_assert(so);
sewardjb4112022007-11-09 22:49:28 +00002529 VG_(dropTailXA)( xa, 1 );
sewardjf98e1c02008-10-25 16:22:41 +00002530 return so;
sewardjb4112022007-11-09 22:49:28 +00002531 } else {
2532 /* hmm, that's odd. No stack for this semaphore. */
2533 return NULL;
2534 }
2535}
2536
sewardj11e352f2007-11-30 11:11:02 +00002537static void evh__HG_POSIX_SEM_DESTROY_PRE ( ThreadId tid, void* sem )
sewardjb4112022007-11-09 22:49:28 +00002538{
sewardjf98e1c02008-10-25 16:22:41 +00002539 UWord keyW, valW;
2540 SO* so;
sewardjb4112022007-11-09 22:49:28 +00002541
sewardjb4112022007-11-09 22:49:28 +00002542 if (SHOW_EVENTS >= 1)
sewardj11e352f2007-11-30 11:11:02 +00002543 VG_(printf)("evh__HG_POSIX_SEM_DESTROY_PRE(ctid=%d, sem=%p)\n",
sewardjb4112022007-11-09 22:49:28 +00002544 (Int)tid, (void*)sem );
2545
sewardjf98e1c02008-10-25 16:22:41 +00002546 map_sem_to_SO_stack_INIT();
sewardjb4112022007-11-09 22:49:28 +00002547
sewardjf98e1c02008-10-25 16:22:41 +00002548 /* Empty out the semaphore's SO stack. This way of doing it is
2549 stupid, but at least it's easy. */
2550 while (1) {
2551 so = mb_pop_SO_for_sem( sem );
2552 if (!so) break;
2553 libhb_so_dealloc(so);
2554 }
2555
2556 if (VG_(delFromFM)( map_sem_to_SO_stack, &keyW, &valW, (UWord)sem )) {
2557 XArray* xa = (XArray*)valW;
2558 tl_assert(keyW == (UWord)sem);
2559 tl_assert(xa);
2560 tl_assert(VG_(sizeXA)(xa) == 0); /* preceding loop just emptied it */
2561 VG_(deleteXA)(xa);
2562 }
sewardjb4112022007-11-09 22:49:28 +00002563}
2564
sewardj11e352f2007-11-30 11:11:02 +00002565static
2566void evh__HG_POSIX_SEM_INIT_POST ( ThreadId tid, void* sem, UWord value )
2567{
sewardjf98e1c02008-10-25 16:22:41 +00002568 SO* so;
2569 Thread* thr;
sewardj11e352f2007-11-30 11:11:02 +00002570
2571 if (SHOW_EVENTS >= 1)
2572 VG_(printf)("evh__HG_POSIX_SEM_INIT_POST(ctid=%d, sem=%p, value=%lu)\n",
2573 (Int)tid, (void*)sem, value );
2574
sewardjf98e1c02008-10-25 16:22:41 +00002575 thr = map_threads_maybe_lookup( tid );
2576 tl_assert(thr); /* cannot fail - Thread* must already exist */
sewardj11e352f2007-11-30 11:11:02 +00002577
sewardjf98e1c02008-10-25 16:22:41 +00002578 /* Empty out the semaphore's SO stack. This way of doing it is
2579 stupid, but at least it's easy. */
2580 while (1) {
2581 so = mb_pop_SO_for_sem( sem );
2582 if (!so) break;
2583 libhb_so_dealloc(so);
2584 }
sewardj11e352f2007-11-30 11:11:02 +00002585
sewardjf98e1c02008-10-25 16:22:41 +00002586 /* If we don't do this check, the following while loop runs us out
2587 of memory for stupid initial values of 'value'. */
2588 if (value > 10000) {
2589 HG_(record_error_Misc)(
2590 thr, "sem_init: initial value exceeds 10000; using 10000" );
2591 value = 10000;
2592 }
sewardj11e352f2007-11-30 11:11:02 +00002593
sewardjf98e1c02008-10-25 16:22:41 +00002594 /* Now create 'valid' new SOs for the thread, do a strong send to
2595 each of them, and push them all on the stack. */
2596 for (; value > 0; value--) {
2597 Thr* hbthr = thr->hbthr;
2598 tl_assert(hbthr);
sewardj11e352f2007-11-30 11:11:02 +00002599
sewardjf98e1c02008-10-25 16:22:41 +00002600 so = libhb_so_alloc();
2601 libhb_so_send( hbthr, so, True/*strong send*/ );
2602 push_SO_for_sem( sem, so );
sewardj11e352f2007-11-30 11:11:02 +00002603 }
2604}
2605
2606static void evh__HG_POSIX_SEM_POST_PRE ( ThreadId tid, void* sem )
sewardjb4112022007-11-09 22:49:28 +00002607{
sewardjf98e1c02008-10-25 16:22:41 +00002608 /* 'tid' has posted on 'sem'. Create a new SO, do a strong send to
2609 it (iow, write our VC into it, then tick ours), and push the SO
2610 on on a stack of SOs associated with 'sem'. This is later used
2611 by other thread(s) which successfully exit from a sem_wait on
2612 the same sem; by doing a strong recv from SOs popped of the
2613 stack, they acquire dependencies on the posting thread
2614 segment(s). */
sewardjb4112022007-11-09 22:49:28 +00002615
sewardjf98e1c02008-10-25 16:22:41 +00002616 Thread* thr;
2617 SO* so;
2618 Thr* hbthr;
sewardjb4112022007-11-09 22:49:28 +00002619
2620 if (SHOW_EVENTS >= 1)
sewardj11e352f2007-11-30 11:11:02 +00002621 VG_(printf)("evh__HG_POSIX_SEM_POST_PRE(ctid=%d, sem=%p)\n",
sewardjb4112022007-11-09 22:49:28 +00002622 (Int)tid, (void*)sem );
2623
2624 thr = map_threads_maybe_lookup( tid );
2625 tl_assert(thr); /* cannot fail - Thread* must already exist */
2626
2627 // error-if: sem is bogus
2628
sewardjf98e1c02008-10-25 16:22:41 +00002629 hbthr = thr->hbthr;
2630 tl_assert(hbthr);
sewardjb4112022007-11-09 22:49:28 +00002631
sewardjf98e1c02008-10-25 16:22:41 +00002632 so = libhb_so_alloc();
2633 libhb_so_send( hbthr, so, True/*strong send*/ );
2634 push_SO_for_sem( sem, so );
sewardjb4112022007-11-09 22:49:28 +00002635}
2636
sewardj11e352f2007-11-30 11:11:02 +00002637static void evh__HG_POSIX_SEM_WAIT_POST ( ThreadId tid, void* sem )
sewardjb4112022007-11-09 22:49:28 +00002638{
sewardjf98e1c02008-10-25 16:22:41 +00002639 /* A sem_wait(sem) completed successfully. Pop the posting-SO for
2640 the 'sem' from this semaphore's SO-stack, and do a strong recv
2641 from it. This creates a dependency back to one of the post-ers
2642 for the semaphore. */
sewardjb4112022007-11-09 22:49:28 +00002643
sewardjf98e1c02008-10-25 16:22:41 +00002644 Thread* thr;
2645 SO* so;
2646 Thr* hbthr;
sewardjb4112022007-11-09 22:49:28 +00002647
2648 if (SHOW_EVENTS >= 1)
sewardj11e352f2007-11-30 11:11:02 +00002649 VG_(printf)("evh__HG_POSIX_SEM_WAIT_POST(ctid=%d, sem=%p)\n",
sewardjb4112022007-11-09 22:49:28 +00002650 (Int)tid, (void*)sem );
2651
2652 thr = map_threads_maybe_lookup( tid );
2653 tl_assert(thr); /* cannot fail - Thread* must already exist */
2654
2655 // error-if: sem is bogus
2656
sewardjf98e1c02008-10-25 16:22:41 +00002657 so = mb_pop_SO_for_sem( sem );
sewardjb4112022007-11-09 22:49:28 +00002658
sewardjf98e1c02008-10-25 16:22:41 +00002659 if (so) {
2660 hbthr = thr->hbthr;
2661 tl_assert(hbthr);
2662
2663 libhb_so_recv( hbthr, so, True/*strong recv*/ );
2664 libhb_so_dealloc(so);
2665 } else {
2666 /* Hmm. How can a wait on 'sem' succeed if nobody posted to it?
2667 If this happened it would surely be a bug in the threads
2668 library. */
2669 HG_(record_error_Misc)(
2670 thr, "Bug in libpthread: sem_wait succeeded on"
2671 " semaphore without prior sem_post");
sewardjb4112022007-11-09 22:49:28 +00002672 }
2673}
2674
2675
sewardj9f569b72008-11-13 13:33:09 +00002676/* -------------------------------------------------------- */
2677/* -------------- events to do with barriers -------------- */
2678/* -------------------------------------------------------- */
2679
2680typedef
2681 struct {
2682 Bool initted; /* has it yet been initted by guest? */
sewardj406bac82010-03-03 23:03:40 +00002683 Bool resizable; /* is resizing allowed? */
sewardj9f569b72008-11-13 13:33:09 +00002684 UWord size; /* declared size */
2685 XArray* waiting; /* XA of Thread*. # present is 0 .. .size */
2686 }
2687 Bar;
2688
2689static Bar* new_Bar ( void ) {
2690 Bar* bar = HG_(zalloc)( "hg.nB.1 (new_Bar)", sizeof(Bar) );
2691 tl_assert(bar);
2692 /* all fields are zero */
2693 tl_assert(bar->initted == False);
2694 return bar;
2695}
2696
2697static void delete_Bar ( Bar* bar ) {
2698 tl_assert(bar);
2699 if (bar->waiting)
2700 VG_(deleteXA)(bar->waiting);
2701 HG_(free)(bar);
2702}
2703
2704/* A mapping which stores auxiliary data for barriers. */
2705
2706/* pthread_barrier_t* -> Bar* */
2707static WordFM* map_barrier_to_Bar = NULL;
2708
2709static void map_barrier_to_Bar_INIT ( void ) {
2710 if (UNLIKELY(map_barrier_to_Bar == NULL)) {
2711 map_barrier_to_Bar = VG_(newFM)( HG_(zalloc),
2712 "hg.mbtBI.1", HG_(free), NULL );
2713 tl_assert(map_barrier_to_Bar != NULL);
2714 }
2715}
2716
2717static Bar* map_barrier_to_Bar_lookup_or_alloc ( void* barrier ) {
2718 UWord key, val;
2719 map_barrier_to_Bar_INIT();
2720 if (VG_(lookupFM)( map_barrier_to_Bar, &key, &val, (UWord)barrier )) {
2721 tl_assert(key == (UWord)barrier);
2722 return (Bar*)val;
2723 } else {
2724 Bar* bar = new_Bar();
2725 VG_(addToFM)( map_barrier_to_Bar, (UWord)barrier, (UWord)bar );
2726 return bar;
2727 }
2728}
2729
2730static void map_barrier_to_Bar_delete ( void* barrier ) {
2731 UWord keyW, valW;
2732 map_barrier_to_Bar_INIT();
2733 if (VG_(delFromFM)( map_barrier_to_Bar, &keyW, &valW, (UWord)barrier )) {
2734 Bar* bar = (Bar*)valW;
2735 tl_assert(keyW == (UWord)barrier);
2736 delete_Bar(bar);
2737 }
2738}
2739
2740
2741static void evh__HG_PTHREAD_BARRIER_INIT_PRE ( ThreadId tid,
2742 void* barrier,
sewardj406bac82010-03-03 23:03:40 +00002743 UWord count,
2744 UWord resizable )
sewardj9f569b72008-11-13 13:33:09 +00002745{
2746 Thread* thr;
2747 Bar* bar;
2748
2749 if (SHOW_EVENTS >= 1)
2750 VG_(printf)("evh__HG_PTHREAD_BARRIER_INIT_PRE"
sewardj406bac82010-03-03 23:03:40 +00002751 "(tid=%d, barrier=%p, count=%lu, resizable=%lu)\n",
2752 (Int)tid, (void*)barrier, count, resizable );
sewardj9f569b72008-11-13 13:33:09 +00002753
2754 thr = map_threads_maybe_lookup( tid );
2755 tl_assert(thr); /* cannot fail - Thread* must already exist */
2756
2757 if (count == 0) {
2758 HG_(record_error_Misc)(
2759 thr, "pthread_barrier_init: 'count' argument is zero"
2760 );
2761 }
2762
sewardj406bac82010-03-03 23:03:40 +00002763 if (resizable != 0 && resizable != 1) {
2764 HG_(record_error_Misc)(
2765 thr, "pthread_barrier_init: invalid 'resizable' argument"
2766 );
2767 }
2768
sewardj9f569b72008-11-13 13:33:09 +00002769 bar = map_barrier_to_Bar_lookup_or_alloc(barrier);
2770 tl_assert(bar);
2771
2772 if (bar->initted) {
2773 HG_(record_error_Misc)(
2774 thr, "pthread_barrier_init: barrier is already initialised"
2775 );
2776 }
2777
2778 if (bar->waiting && VG_(sizeXA)(bar->waiting) > 0) {
2779 tl_assert(bar->initted);
2780 HG_(record_error_Misc)(
sewardj553655c2008-11-14 19:41:19 +00002781 thr, "pthread_barrier_init: threads are waiting at barrier"
sewardj9f569b72008-11-13 13:33:09 +00002782 );
2783 VG_(dropTailXA)(bar->waiting, VG_(sizeXA)(bar->waiting));
2784 }
2785 if (!bar->waiting) {
2786 bar->waiting = VG_(newXA)( HG_(zalloc), "hg.eHPBIP.1", HG_(free),
2787 sizeof(Thread*) );
2788 }
2789
2790 tl_assert(bar->waiting);
2791 tl_assert(VG_(sizeXA)(bar->waiting) == 0);
sewardj406bac82010-03-03 23:03:40 +00002792 bar->initted = True;
2793 bar->resizable = resizable == 1 ? True : False;
2794 bar->size = count;
sewardj9f569b72008-11-13 13:33:09 +00002795}
2796
2797
2798static void evh__HG_PTHREAD_BARRIER_DESTROY_PRE ( ThreadId tid,
2799 void* barrier )
2800{
sewardj553655c2008-11-14 19:41:19 +00002801 Thread* thr;
2802 Bar* bar;
2803
sewardj9f569b72008-11-13 13:33:09 +00002804 /* Deal with destroy events. The only purpose is to free storage
2805 associated with the barrier, so as to avoid any possible
2806 resource leaks. */
2807 if (SHOW_EVENTS >= 1)
2808 VG_(printf)("evh__HG_PTHREAD_BARRIER_DESTROY_PRE"
2809 "(tid=%d, barrier=%p)\n",
2810 (Int)tid, (void*)barrier );
2811
sewardj553655c2008-11-14 19:41:19 +00002812 thr = map_threads_maybe_lookup( tid );
2813 tl_assert(thr); /* cannot fail - Thread* must already exist */
2814
2815 bar = map_barrier_to_Bar_lookup_or_alloc(barrier);
2816 tl_assert(bar);
2817
2818 if (!bar->initted) {
2819 HG_(record_error_Misc)(
2820 thr, "pthread_barrier_destroy: barrier was never initialised"
2821 );
2822 }
2823
2824 if (bar->initted && bar->waiting && VG_(sizeXA)(bar->waiting) > 0) {
2825 HG_(record_error_Misc)(
2826 thr, "pthread_barrier_destroy: threads are waiting at barrier"
2827 );
2828 }
2829
sewardj9f569b72008-11-13 13:33:09 +00002830 /* Maybe we shouldn't do this; just let it persist, so that when it
2831 is reinitialised we don't need to do any dynamic memory
2832 allocation? The downside is a potentially unlimited space leak,
2833 if the client creates (in turn) a large number of barriers all
2834 at different locations. Note that if we do later move to the
2835 don't-delete-it scheme, we need to mark the barrier as
2836 uninitialised again since otherwise a later _init call will
sewardj553655c2008-11-14 19:41:19 +00002837 elicit a duplicate-init error. */
sewardj9f569b72008-11-13 13:33:09 +00002838 map_barrier_to_Bar_delete( barrier );
2839}
2840
2841
sewardj406bac82010-03-03 23:03:40 +00002842/* All the threads have arrived. Now do the Interesting Bit. Get a
2843 new synchronisation object and do a weak send to it from all the
2844 participating threads. This makes its vector clocks be the join of
2845 all the individual threads' vector clocks. Then do a strong
2846 receive from it back to all threads, so that their VCs are a copy
2847 of it (hence are all equal to the join of their original VCs.) */
2848static void do_barrier_cross_sync_and_empty ( Bar* bar )
2849{
2850 /* XXX check bar->waiting has no duplicates */
2851 UWord i;
2852 SO* so = libhb_so_alloc();
2853
2854 tl_assert(bar->waiting);
2855 tl_assert(VG_(sizeXA)(bar->waiting) == bar->size);
2856
2857 /* compute the join ... */
2858 for (i = 0; i < bar->size; i++) {
2859 Thread* t = *(Thread**)VG_(indexXA)(bar->waiting, i);
2860 Thr* hbthr = t->hbthr;
2861 libhb_so_send( hbthr, so, False/*weak send*/ );
2862 }
2863 /* ... and distribute to all threads */
2864 for (i = 0; i < bar->size; i++) {
2865 Thread* t = *(Thread**)VG_(indexXA)(bar->waiting, i);
2866 Thr* hbthr = t->hbthr;
2867 libhb_so_recv( hbthr, so, True/*strong recv*/ );
2868 }
2869
2870 /* finally, we must empty out the waiting vector */
2871 VG_(dropTailXA)(bar->waiting, VG_(sizeXA)(bar->waiting));
2872
2873 /* and we don't need this any more. Perhaps a stack-allocated
2874 SO would be better? */
2875 libhb_so_dealloc(so);
2876}
2877
2878
sewardj9f569b72008-11-13 13:33:09 +00002879static void evh__HG_PTHREAD_BARRIER_WAIT_PRE ( ThreadId tid,
2880 void* barrier )
2881{
sewardj1c466b72008-11-19 11:52:14 +00002882 /* This function gets called after a client thread calls
2883 pthread_barrier_wait but before it arrives at the real
2884 pthread_barrier_wait.
2885
2886 Why is the following correct? It's a bit subtle.
2887
2888 If this is not the last thread arriving at the barrier, we simply
2889 note its presence and return. Because valgrind (at least as of
2890 Nov 08) is single threaded, we are guaranteed safe from any race
2891 conditions when in this function -- no other client threads are
2892 running.
2893
2894 If this is the last thread, then we are again the only running
2895 thread. All the other threads will have either arrived at the
2896 real pthread_barrier_wait or are on their way to it, but in any
2897 case are guaranteed not to be able to move past it, because this
2898 thread is currently in this function and so has not yet arrived
2899 at the real pthread_barrier_wait. That means that:
2900
2901 1. While we are in this function, none of the other threads
2902 waiting at the barrier can move past it.
2903
2904 2. When this function returns (and simulated execution resumes),
2905 this thread and all other waiting threads will be able to move
2906 past the real barrier.
2907
2908 Because of this, it is now safe to update the vector clocks of
2909 all threads, to represent the fact that they all arrived at the
2910 barrier and have all moved on. There is no danger of any
2911 complications to do with some threads leaving the barrier and
2912 racing back round to the front, whilst others are still leaving
2913 (which is the primary source of complication in correct handling/
2914 implementation of barriers). That can't happen because we update
2915 here our data structures so as to indicate that the threads have
2916 passed the barrier, even though, as per (2) above, they are
2917 guaranteed not to pass the barrier until we return.
2918
2919 This relies crucially on Valgrind being single threaded. If that
2920 changes, this will need to be reconsidered.
2921 */
sewardj9f569b72008-11-13 13:33:09 +00002922 Thread* thr;
2923 Bar* bar;
sewardj406bac82010-03-03 23:03:40 +00002924 UWord present;
sewardj9f569b72008-11-13 13:33:09 +00002925
2926 if (SHOW_EVENTS >= 1)
2927 VG_(printf)("evh__HG_PTHREAD_BARRIER_WAIT_PRE"
2928 "(tid=%d, barrier=%p)\n",
2929 (Int)tid, (void*)barrier );
2930
2931 thr = map_threads_maybe_lookup( tid );
2932 tl_assert(thr); /* cannot fail - Thread* must already exist */
2933
2934 bar = map_barrier_to_Bar_lookup_or_alloc(barrier);
2935 tl_assert(bar);
2936
2937 if (!bar->initted) {
2938 HG_(record_error_Misc)(
2939 thr, "pthread_barrier_wait: barrier is uninitialised"
2940 );
2941 return; /* client is broken .. avoid assertions below */
2942 }
2943
2944 /* guaranteed by _INIT_PRE above */
2945 tl_assert(bar->size > 0);
2946 tl_assert(bar->waiting);
2947
2948 VG_(addToXA)( bar->waiting, &thr );
2949
2950 /* guaranteed by this function */
2951 present = VG_(sizeXA)(bar->waiting);
2952 tl_assert(present > 0 && present <= bar->size);
2953
2954 if (present < bar->size)
2955 return;
2956
sewardj406bac82010-03-03 23:03:40 +00002957 do_barrier_cross_sync_and_empty(bar);
2958}
sewardj9f569b72008-11-13 13:33:09 +00002959
sewardj9f569b72008-11-13 13:33:09 +00002960
sewardj406bac82010-03-03 23:03:40 +00002961static void evh__HG_PTHREAD_BARRIER_RESIZE_PRE ( ThreadId tid,
2962 void* barrier,
2963 UWord newcount )
2964{
2965 Thread* thr;
2966 Bar* bar;
2967 UWord present;
2968
2969 if (SHOW_EVENTS >= 1)
2970 VG_(printf)("evh__HG_PTHREAD_BARRIER_RESIZE_PRE"
2971 "(tid=%d, barrier=%p, newcount=%lu)\n",
2972 (Int)tid, (void*)barrier, newcount );
2973
2974 thr = map_threads_maybe_lookup( tid );
2975 tl_assert(thr); /* cannot fail - Thread* must already exist */
2976
2977 bar = map_barrier_to_Bar_lookup_or_alloc(barrier);
2978 tl_assert(bar);
2979
2980 if (!bar->initted) {
2981 HG_(record_error_Misc)(
2982 thr, "pthread_barrier_resize: barrier is uninitialised"
2983 );
2984 return; /* client is broken .. avoid assertions below */
2985 }
2986
2987 if (!bar->resizable) {
2988 HG_(record_error_Misc)(
2989 thr, "pthread_barrier_resize: barrier is may not be resized"
2990 );
2991 return; /* client is broken .. avoid assertions below */
2992 }
2993
2994 if (newcount == 0) {
2995 HG_(record_error_Misc)(
2996 thr, "pthread_barrier_resize: 'newcount' argument is zero"
2997 );
2998 return; /* client is broken .. avoid assertions below */
2999 }
3000
3001 /* guaranteed by _INIT_PRE above */
3002 tl_assert(bar->size > 0);
sewardj9f569b72008-11-13 13:33:09 +00003003 tl_assert(bar->waiting);
sewardj406bac82010-03-03 23:03:40 +00003004 /* Guaranteed by this fn */
3005 tl_assert(newcount > 0);
sewardj9f569b72008-11-13 13:33:09 +00003006
sewardj406bac82010-03-03 23:03:40 +00003007 if (newcount >= bar->size) {
3008 /* Increasing the capacity. There's no possibility of threads
3009 moving on from the barrier in this situation, so just note
3010 the fact and do nothing more. */
3011 bar->size = newcount;
3012 } else {
3013 /* Decreasing the capacity. If we decrease it to be equal or
3014 below the number of waiting threads, they will now move past
3015 the barrier, so need to mess with dep edges in the same way
3016 as if the barrier had filled up normally. */
3017 present = VG_(sizeXA)(bar->waiting);
3018 tl_assert(present >= 0 && present <= bar->size);
3019 if (newcount <= present) {
3020 bar->size = present; /* keep the cross_sync call happy */
3021 do_barrier_cross_sync_and_empty(bar);
3022 }
3023 bar->size = newcount;
sewardj9f569b72008-11-13 13:33:09 +00003024 }
sewardj9f569b72008-11-13 13:33:09 +00003025}
3026
3027
sewardjed2e72e2009-08-14 11:08:24 +00003028/* ----------------------------------------------------- */
3029/* ----- events to do with user-specified HB edges ----- */
3030/* ----------------------------------------------------- */
3031
3032/* A mapping from arbitrary UWord tag to the SO associated with it.
3033 The UWord tags are meaningless to us, interpreted only by the
3034 user. */
3035
3036
3037
3038/* UWord -> SO* */
3039static WordFM* map_usertag_to_SO = NULL;
3040
3041static void map_usertag_to_SO_INIT ( void ) {
3042 if (UNLIKELY(map_usertag_to_SO == NULL)) {
3043 map_usertag_to_SO = VG_(newFM)( HG_(zalloc),
3044 "hg.mutS.1", HG_(free), NULL );
3045 tl_assert(map_usertag_to_SO != NULL);
3046 }
3047}
3048
3049static SO* map_usertag_to_SO_lookup_or_alloc ( UWord usertag ) {
3050 UWord key, val;
3051 map_usertag_to_SO_INIT();
3052 if (VG_(lookupFM)( map_usertag_to_SO, &key, &val, usertag )) {
3053 tl_assert(key == (UWord)usertag);
3054 return (SO*)val;
3055 } else {
3056 SO* so = libhb_so_alloc();
3057 VG_(addToFM)( map_usertag_to_SO, usertag, (UWord)so );
3058 return so;
3059 }
3060}
3061
sewardj6015d0e2011-03-11 19:10:48 +00003062static void map_usertag_to_SO_delete ( UWord usertag ) {
3063 UWord keyW, valW;
3064 map_usertag_to_SO_INIT();
3065 if (VG_(delFromFM)( map_usertag_to_SO, &keyW, &valW, usertag )) {
3066 SO* so = (SO*)valW;
3067 tl_assert(keyW == usertag);
3068 tl_assert(so);
3069 libhb_so_dealloc(so);
3070 }
3071}
sewardjed2e72e2009-08-14 11:08:24 +00003072
3073
3074static
3075void evh__HG_USERSO_SEND_PRE ( ThreadId tid, UWord usertag )
3076{
3077 /* TID is just about to notionally sent a message on a notional
3078 abstract synchronisation object whose identity is given by
3079 USERTAG. Bind USERTAG to a real SO if it is not already so
sewardj8c50d3c2011-03-11 18:38:12 +00003080 bound, and do a 'weak send' on the SO. This joins the vector
3081 clocks from this thread into any vector clocks already present
3082 in the SO. The resulting SO vector clocks are later used by
sewardjed2e72e2009-08-14 11:08:24 +00003083 other thread(s) which successfully 'receive' from the SO,
sewardj8c50d3c2011-03-11 18:38:12 +00003084 thereby acquiring a dependency on all the events that have
3085 previously signalled on this SO. */
sewardjed2e72e2009-08-14 11:08:24 +00003086 Thread* thr;
3087 SO* so;
3088
3089 if (SHOW_EVENTS >= 1)
3090 VG_(printf)("evh__HG_USERSO_SEND_PRE(ctid=%d, usertag=%#lx)\n",
3091 (Int)tid, usertag );
3092
3093 thr = map_threads_maybe_lookup( tid );
3094 tl_assert(thr); /* cannot fail - Thread* must already exist */
3095
3096 so = map_usertag_to_SO_lookup_or_alloc( usertag );
3097 tl_assert(so);
3098
sewardj8c50d3c2011-03-11 18:38:12 +00003099 libhb_so_send( thr->hbthr, so, False/*!strong_send*/ );
sewardjed2e72e2009-08-14 11:08:24 +00003100}
3101
3102static
3103void evh__HG_USERSO_RECV_POST ( ThreadId tid, UWord usertag )
3104{
3105 /* TID has just notionally received a message from a notional
3106 abstract synchronisation object whose identity is given by
3107 USERTAG. Bind USERTAG to a real SO if it is not already so
3108 bound. If the SO has at some point in the past been 'sent' on,
3109 to a 'strong receive' on it, thereby acquiring a dependency on
3110 the sender. */
3111 Thread* thr;
3112 SO* so;
3113
3114 if (SHOW_EVENTS >= 1)
3115 VG_(printf)("evh__HG_USERSO_RECV_POST(ctid=%d, usertag=%#lx)\n",
3116 (Int)tid, usertag );
3117
3118 thr = map_threads_maybe_lookup( tid );
3119 tl_assert(thr); /* cannot fail - Thread* must already exist */
3120
3121 so = map_usertag_to_SO_lookup_or_alloc( usertag );
3122 tl_assert(so);
3123
3124 /* Acquire a dependency on it. If the SO has never so far been
3125 sent on, then libhb_so_recv will do nothing. So we're safe
3126 regardless of SO's history. */
3127 libhb_so_recv( thr->hbthr, so, True/*strong_recv*/ );
3128}
3129
sewardj6015d0e2011-03-11 19:10:48 +00003130static
3131void evh__HG_USERSO_FORGET_ALL ( ThreadId tid, UWord usertag )
3132{
3133 /* TID declares that any happens-before edges notionally stored in
3134 USERTAG can be deleted. If (as would normally be the case) a
3135 SO is associated with USERTAG, then the assocation is removed
3136 and all resources associated with SO are freed. Importantly,
3137 that frees up any VTSs stored in SO. */
3138 if (SHOW_EVENTS >= 1)
3139 VG_(printf)("evh__HG_USERSO_FORGET_ALL(ctid=%d, usertag=%#lx)\n",
3140 (Int)tid, usertag );
3141
3142 map_usertag_to_SO_delete( usertag );
3143}
3144
sewardjed2e72e2009-08-14 11:08:24 +00003145
sewardjb4112022007-11-09 22:49:28 +00003146/*--------------------------------------------------------------*/
3147/*--- Lock acquisition order monitoring ---*/
3148/*--------------------------------------------------------------*/
3149
3150/* FIXME: here are some optimisations still to do in
3151 laog__pre_thread_acquires_lock.
3152
3153 The graph is structured so that if L1 --*--> L2 then L1 must be
3154 acquired before L2.
3155
3156 The common case is that some thread T holds (eg) L1 L2 and L3 and
3157 is repeatedly acquiring and releasing Ln, and there is no ordering
3158 error in what it is doing. Hence it repeatly:
3159
3160 (1) searches laog to see if Ln --*--> {L1,L2,L3}, which always
3161 produces the answer No (because there is no error).
3162
3163 (2) adds edges {L1,L2,L3} --> Ln to laog, which are already present
3164 (because they already got added the first time T acquired Ln).
3165
3166 Hence cache these two events:
3167
3168 (1) Cache result of the query from last time. Invalidate the cache
3169 any time any edges are added to or deleted from laog.
3170
3171 (2) Cache these add-edge requests and ignore them if said edges
3172 have already been added to laog. Invalidate the cache any time
3173 any edges are deleted from laog.
3174*/
3175
3176typedef
3177 struct {
3178 WordSetID inns; /* in univ_laog */
3179 WordSetID outs; /* in univ_laog */
3180 }
3181 LAOGLinks;
3182
3183/* lock order acquisition graph */
3184static WordFM* laog = NULL; /* WordFM Lock* LAOGLinks* */
3185
3186/* EXPOSITION ONLY: for each edge in 'laog', record the two places
3187 where that edge was created, so that we can show the user later if
3188 we need to. */
3189typedef
3190 struct {
3191 Addr src_ga; /* Lock guest addresses for */
3192 Addr dst_ga; /* src/dst of the edge */
3193 ExeContext* src_ec; /* And corresponding places where that */
3194 ExeContext* dst_ec; /* ordering was established */
3195 }
3196 LAOGLinkExposition;
3197
sewardj250ec2e2008-02-15 22:02:30 +00003198static Word cmp_LAOGLinkExposition ( UWord llx1W, UWord llx2W ) {
sewardjb4112022007-11-09 22:49:28 +00003199 /* Compare LAOGLinkExposition*s by (src_ga,dst_ga) field pair. */
3200 LAOGLinkExposition* llx1 = (LAOGLinkExposition*)llx1W;
3201 LAOGLinkExposition* llx2 = (LAOGLinkExposition*)llx2W;
3202 if (llx1->src_ga < llx2->src_ga) return -1;
3203 if (llx1->src_ga > llx2->src_ga) return 1;
3204 if (llx1->dst_ga < llx2->dst_ga) return -1;
3205 if (llx1->dst_ga > llx2->dst_ga) return 1;
3206 return 0;
3207}
3208
3209static WordFM* laog_exposition = NULL; /* WordFM LAOGLinkExposition* NULL */
3210/* end EXPOSITION ONLY */
3211
3212
sewardja65db102009-01-26 10:45:16 +00003213__attribute__((noinline))
3214static void laog__init ( void )
3215{
3216 tl_assert(!laog);
3217 tl_assert(!laog_exposition);
sewardjc1fb9d22011-02-28 09:03:44 +00003218 tl_assert(HG_(clo_track_lockorders));
sewardja65db102009-01-26 10:45:16 +00003219
3220 laog = VG_(newFM)( HG_(zalloc), "hg.laog__init.1",
3221 HG_(free), NULL/*unboxedcmp*/ );
3222
3223 laog_exposition = VG_(newFM)( HG_(zalloc), "hg.laog__init.2", HG_(free),
3224 cmp_LAOGLinkExposition );
3225 tl_assert(laog);
3226 tl_assert(laog_exposition);
3227}
3228
sewardjb4112022007-11-09 22:49:28 +00003229static void laog__show ( Char* who ) {
3230 Word i, ws_size;
sewardj250ec2e2008-02-15 22:02:30 +00003231 UWord* ws_words;
sewardjb4112022007-11-09 22:49:28 +00003232 Lock* me;
3233 LAOGLinks* links;
3234 VG_(printf)("laog (requested by %s) {\n", who);
sewardj896f6f92008-08-19 08:38:52 +00003235 VG_(initIterFM)( laog );
sewardjb4112022007-11-09 22:49:28 +00003236 me = NULL;
3237 links = NULL;
sewardj896f6f92008-08-19 08:38:52 +00003238 while (VG_(nextIterFM)( laog, (Word*)&me,
sewardjb5f29642007-11-16 12:02:43 +00003239 (Word*)&links )) {
sewardjb4112022007-11-09 22:49:28 +00003240 tl_assert(me);
3241 tl_assert(links);
3242 VG_(printf)(" node %p:\n", me);
3243 HG_(getPayloadWS)( &ws_words, &ws_size, univ_laog, links->inns );
3244 for (i = 0; i < ws_size; i++)
barta0b6b2c2008-07-07 06:49:24 +00003245 VG_(printf)(" inn %#lx\n", ws_words[i] );
sewardjb4112022007-11-09 22:49:28 +00003246 HG_(getPayloadWS)( &ws_words, &ws_size, univ_laog, links->outs );
3247 for (i = 0; i < ws_size; i++)
barta0b6b2c2008-07-07 06:49:24 +00003248 VG_(printf)(" out %#lx\n", ws_words[i] );
sewardjb4112022007-11-09 22:49:28 +00003249 me = NULL;
3250 links = NULL;
3251 }
sewardj896f6f92008-08-19 08:38:52 +00003252 VG_(doneIterFM)( laog );
sewardjb4112022007-11-09 22:49:28 +00003253 VG_(printf)("}\n");
3254}
3255
3256__attribute__((noinline))
3257static void laog__add_edge ( Lock* src, Lock* dst ) {
3258 Word keyW;
3259 LAOGLinks* links;
3260 Bool presentF, presentR;
3261 if (0) VG_(printf)("laog__add_edge %p %p\n", src, dst);
3262
3263 /* Take the opportunity to sanity check the graph. Record in
3264 presentF if there is already a src->dst mapping in this node's
3265 forwards links, and presentR if there is already a src->dst
3266 mapping in this node's backwards links. They should agree!
3267 Also, we need to know whether the edge was already present so as
3268 to decide whether or not to update the link details mapping. We
3269 can compute presentF and presentR essentially for free, so may
3270 as well do this always. */
3271 presentF = presentR = False;
3272
3273 /* Update the out edges for src */
3274 keyW = 0;
3275 links = NULL;
sewardj896f6f92008-08-19 08:38:52 +00003276 if (VG_(lookupFM)( laog, &keyW, (Word*)&links, (Word)src )) {
sewardjb4112022007-11-09 22:49:28 +00003277 WordSetID outs_new;
3278 tl_assert(links);
3279 tl_assert(keyW == (Word)src);
3280 outs_new = HG_(addToWS)( univ_laog, links->outs, (Word)dst );
3281 presentF = outs_new == links->outs;
3282 links->outs = outs_new;
3283 } else {
sewardjf98e1c02008-10-25 16:22:41 +00003284 links = HG_(zalloc)("hg.lae.1", sizeof(LAOGLinks));
sewardjb4112022007-11-09 22:49:28 +00003285 links->inns = HG_(emptyWS)( univ_laog );
3286 links->outs = HG_(singletonWS)( univ_laog, (Word)dst );
sewardj896f6f92008-08-19 08:38:52 +00003287 VG_(addToFM)( laog, (Word)src, (Word)links );
sewardjb4112022007-11-09 22:49:28 +00003288 }
3289 /* Update the in edges for dst */
3290 keyW = 0;
3291 links = NULL;
sewardj896f6f92008-08-19 08:38:52 +00003292 if (VG_(lookupFM)( laog, &keyW, (Word*)&links, (Word)dst )) {
sewardjb4112022007-11-09 22:49:28 +00003293 WordSetID inns_new;
3294 tl_assert(links);
3295 tl_assert(keyW == (Word)dst);
3296 inns_new = HG_(addToWS)( univ_laog, links->inns, (Word)src );
3297 presentR = inns_new == links->inns;
3298 links->inns = inns_new;
3299 } else {
sewardjf98e1c02008-10-25 16:22:41 +00003300 links = HG_(zalloc)("hg.lae.2", sizeof(LAOGLinks));
sewardjb4112022007-11-09 22:49:28 +00003301 links->inns = HG_(singletonWS)( univ_laog, (Word)src );
3302 links->outs = HG_(emptyWS)( univ_laog );
sewardj896f6f92008-08-19 08:38:52 +00003303 VG_(addToFM)( laog, (Word)dst, (Word)links );
sewardjb4112022007-11-09 22:49:28 +00003304 }
3305
3306 tl_assert( (presentF && presentR) || (!presentF && !presentR) );
3307
3308 if (!presentF && src->acquired_at && dst->acquired_at) {
3309 LAOGLinkExposition expo;
3310 /* If this edge is entering the graph, and we have acquired_at
3311 information for both src and dst, record those acquisition
3312 points. Hence, if there is later a violation of this
3313 ordering, we can show the user the two places in which the
3314 required src-dst ordering was previously established. */
barta0b6b2c2008-07-07 06:49:24 +00003315 if (0) VG_(printf)("acquire edge %#lx %#lx\n",
sewardjb4112022007-11-09 22:49:28 +00003316 src->guestaddr, dst->guestaddr);
3317 expo.src_ga = src->guestaddr;
3318 expo.dst_ga = dst->guestaddr;
3319 expo.src_ec = NULL;
3320 expo.dst_ec = NULL;
3321 tl_assert(laog_exposition);
sewardj896f6f92008-08-19 08:38:52 +00003322 if (VG_(lookupFM)( laog_exposition, NULL, NULL, (Word)&expo )) {
sewardjb4112022007-11-09 22:49:28 +00003323 /* we already have it; do nothing */
3324 } else {
sewardjf98e1c02008-10-25 16:22:41 +00003325 LAOGLinkExposition* expo2 = HG_(zalloc)("hg.lae.3",
3326 sizeof(LAOGLinkExposition));
sewardjb4112022007-11-09 22:49:28 +00003327 expo2->src_ga = src->guestaddr;
3328 expo2->dst_ga = dst->guestaddr;
3329 expo2->src_ec = src->acquired_at;
3330 expo2->dst_ec = dst->acquired_at;
sewardj896f6f92008-08-19 08:38:52 +00003331 VG_(addToFM)( laog_exposition, (Word)expo2, (Word)NULL );
sewardjb4112022007-11-09 22:49:28 +00003332 }
3333 }
3334}
3335
3336__attribute__((noinline))
3337static void laog__del_edge ( Lock* src, Lock* dst ) {
3338 Word keyW;
3339 LAOGLinks* links;
3340 if (0) VG_(printf)("laog__del_edge %p %p\n", src, dst);
3341 /* Update the out edges for src */
3342 keyW = 0;
3343 links = NULL;
sewardj896f6f92008-08-19 08:38:52 +00003344 if (VG_(lookupFM)( laog, &keyW, (Word*)&links, (Word)src )) {
sewardjb4112022007-11-09 22:49:28 +00003345 tl_assert(links);
3346 tl_assert(keyW == (Word)src);
3347 links->outs = HG_(delFromWS)( univ_laog, links->outs, (Word)dst );
3348 }
3349 /* Update the in edges for dst */
3350 keyW = 0;
3351 links = NULL;
sewardj896f6f92008-08-19 08:38:52 +00003352 if (VG_(lookupFM)( laog, &keyW, (Word*)&links, (Word)dst )) {
sewardjb4112022007-11-09 22:49:28 +00003353 tl_assert(links);
3354 tl_assert(keyW == (Word)dst);
3355 links->inns = HG_(delFromWS)( univ_laog, links->inns, (Word)src );
3356 }
3357}
3358
3359__attribute__((noinline))
3360static WordSetID /* in univ_laog */ laog__succs ( Lock* lk ) {
3361 Word keyW;
3362 LAOGLinks* links;
3363 keyW = 0;
3364 links = NULL;
sewardj896f6f92008-08-19 08:38:52 +00003365 if (VG_(lookupFM)( laog, &keyW, (Word*)&links, (Word)lk )) {
sewardjb4112022007-11-09 22:49:28 +00003366 tl_assert(links);
3367 tl_assert(keyW == (Word)lk);
3368 return links->outs;
3369 } else {
3370 return HG_(emptyWS)( univ_laog );
3371 }
3372}
3373
3374__attribute__((noinline))
3375static WordSetID /* in univ_laog */ laog__preds ( Lock* lk ) {
3376 Word keyW;
3377 LAOGLinks* links;
3378 keyW = 0;
3379 links = NULL;
sewardj896f6f92008-08-19 08:38:52 +00003380 if (VG_(lookupFM)( laog, &keyW, (Word*)&links, (Word)lk )) {
sewardjb4112022007-11-09 22:49:28 +00003381 tl_assert(links);
3382 tl_assert(keyW == (Word)lk);
3383 return links->inns;
3384 } else {
3385 return HG_(emptyWS)( univ_laog );
3386 }
3387}
3388
3389__attribute__((noinline))
3390static void laog__sanity_check ( Char* who ) {
3391 Word i, ws_size;
sewardj250ec2e2008-02-15 22:02:30 +00003392 UWord* ws_words;
sewardjb4112022007-11-09 22:49:28 +00003393 Lock* me;
3394 LAOGLinks* links;
sewardj896f6f92008-08-19 08:38:52 +00003395 VG_(initIterFM)( laog );
sewardjb4112022007-11-09 22:49:28 +00003396 me = NULL;
3397 links = NULL;
3398 if (0) VG_(printf)("laog sanity check\n");
sewardj896f6f92008-08-19 08:38:52 +00003399 while (VG_(nextIterFM)( laog, (Word*)&me,
sewardjb5f29642007-11-16 12:02:43 +00003400 (Word*)&links )) {
sewardjb4112022007-11-09 22:49:28 +00003401 tl_assert(me);
3402 tl_assert(links);
3403 HG_(getPayloadWS)( &ws_words, &ws_size, univ_laog, links->inns );
3404 for (i = 0; i < ws_size; i++) {
3405 if ( ! HG_(elemWS)( univ_laog,
3406 laog__succs( (Lock*)ws_words[i] ),
3407 (Word)me ))
3408 goto bad;
3409 }
3410 HG_(getPayloadWS)( &ws_words, &ws_size, univ_laog, links->outs );
3411 for (i = 0; i < ws_size; i++) {
3412 if ( ! HG_(elemWS)( univ_laog,
3413 laog__preds( (Lock*)ws_words[i] ),
3414 (Word)me ))
3415 goto bad;
3416 }
3417 me = NULL;
3418 links = NULL;
3419 }
sewardj896f6f92008-08-19 08:38:52 +00003420 VG_(doneIterFM)( laog );
sewardjb4112022007-11-09 22:49:28 +00003421 return;
3422
3423 bad:
3424 VG_(printf)("laog__sanity_check(%s) FAILED\n", who);
3425 laog__show(who);
3426 tl_assert(0);
3427}
3428
3429/* If there is a path in laog from 'src' to any of the elements in
3430 'dst', return an arbitrarily chosen element of 'dst' reachable from
3431 'src'. If no path exist from 'src' to any element in 'dst', return
3432 NULL. */
3433__attribute__((noinline))
3434static
3435Lock* laog__do_dfs_from_to ( Lock* src, WordSetID dsts /* univ_lsets */ )
3436{
3437 Lock* ret;
3438 Word i, ssz;
3439 XArray* stack; /* of Lock* */
3440 WordFM* visited; /* Lock* -> void, iow, Set(Lock*) */
3441 Lock* here;
3442 WordSetID succs;
3443 Word succs_size;
sewardj250ec2e2008-02-15 22:02:30 +00003444 UWord* succs_words;
sewardjb4112022007-11-09 22:49:28 +00003445 //laog__sanity_check();
3446
3447 /* If the destination set is empty, we can never get there from
3448 'src' :-), so don't bother to try */
3449 if (HG_(isEmptyWS)( univ_lsets, dsts ))
3450 return NULL;
3451
3452 ret = NULL;
sewardjf98e1c02008-10-25 16:22:41 +00003453 stack = VG_(newXA)( HG_(zalloc), "hg.lddft.1", HG_(free), sizeof(Lock*) );
3454 visited = VG_(newFM)( HG_(zalloc), "hg.lddft.2", HG_(free), NULL/*unboxedcmp*/ );
sewardjb4112022007-11-09 22:49:28 +00003455
3456 (void) VG_(addToXA)( stack, &src );
3457
3458 while (True) {
3459
3460 ssz = VG_(sizeXA)( stack );
3461
3462 if (ssz == 0) { ret = NULL; break; }
3463
3464 here = *(Lock**) VG_(indexXA)( stack, ssz-1 );
3465 VG_(dropTailXA)( stack, 1 );
3466
3467 if (HG_(elemWS)( univ_lsets, dsts, (Word)here )) { ret = here; break; }
3468
sewardj896f6f92008-08-19 08:38:52 +00003469 if (VG_(lookupFM)( visited, NULL, NULL, (Word)here ))
sewardjb4112022007-11-09 22:49:28 +00003470 continue;
3471
sewardj896f6f92008-08-19 08:38:52 +00003472 VG_(addToFM)( visited, (Word)here, 0 );
sewardjb4112022007-11-09 22:49:28 +00003473
3474 succs = laog__succs( here );
3475 HG_(getPayloadWS)( &succs_words, &succs_size, univ_laog, succs );
3476 for (i = 0; i < succs_size; i++)
3477 (void) VG_(addToXA)( stack, &succs_words[i] );
3478 }
3479
sewardj896f6f92008-08-19 08:38:52 +00003480 VG_(deleteFM)( visited, NULL, NULL );
sewardjb4112022007-11-09 22:49:28 +00003481 VG_(deleteXA)( stack );
3482 return ret;
3483}
3484
3485
3486/* Thread 'thr' is acquiring 'lk'. Check for inconsistent ordering
3487 between 'lk' and the locks already held by 'thr' and issue a
3488 complaint if so. Also, update the ordering graph appropriately.
3489*/
3490__attribute__((noinline))
3491static void laog__pre_thread_acquires_lock (
3492 Thread* thr, /* NB: BEFORE lock is added */
3493 Lock* lk
3494 )
3495{
sewardj250ec2e2008-02-15 22:02:30 +00003496 UWord* ls_words;
sewardjb4112022007-11-09 22:49:28 +00003497 Word ls_size, i;
3498 Lock* other;
3499
3500 /* It may be that 'thr' already holds 'lk' and is recursively
3501 relocking in. In this case we just ignore the call. */
3502 /* NB: univ_lsets really is correct here */
3503 if (HG_(elemWS)( univ_lsets, thr->locksetA, (Word)lk ))
3504 return;
3505
sewardjb4112022007-11-09 22:49:28 +00003506 /* First, the check. Complain if there is any path in laog from lk
3507 to any of the locks already held by thr, since if any such path
3508 existed, it would mean that previously lk was acquired before
3509 (rather than after, as we are doing here) at least one of those
3510 locks.
3511 */
3512 other = laog__do_dfs_from_to(lk, thr->locksetA);
3513 if (other) {
3514 LAOGLinkExposition key, *found;
3515 /* So we managed to find a path lk --*--> other in the graph,
3516 which implies that 'lk' should have been acquired before
3517 'other' but is in fact being acquired afterwards. We present
3518 the lk/other arguments to record_error_LockOrder in the order
3519 in which they should have been acquired. */
3520 /* Go look in the laog_exposition mapping, to find the allocation
3521 points for this edge, so we can show the user. */
3522 key.src_ga = lk->guestaddr;
3523 key.dst_ga = other->guestaddr;
3524 key.src_ec = NULL;
3525 key.dst_ec = NULL;
3526 found = NULL;
sewardj896f6f92008-08-19 08:38:52 +00003527 if (VG_(lookupFM)( laog_exposition,
sewardjb5f29642007-11-16 12:02:43 +00003528 (Word*)&found, NULL, (Word)&key )) {
sewardjb4112022007-11-09 22:49:28 +00003529 tl_assert(found != &key);
3530 tl_assert(found->src_ga == key.src_ga);
3531 tl_assert(found->dst_ga == key.dst_ga);
3532 tl_assert(found->src_ec);
3533 tl_assert(found->dst_ec);
sewardjf98e1c02008-10-25 16:22:41 +00003534 HG_(record_error_LockOrder)(
3535 thr, lk->guestaddr, other->guestaddr,
3536 found->src_ec, found->dst_ec );
sewardjb4112022007-11-09 22:49:28 +00003537 } else {
3538 /* Hmm. This can't happen (can it?) */
sewardjf98e1c02008-10-25 16:22:41 +00003539 HG_(record_error_LockOrder)(
3540 thr, lk->guestaddr, other->guestaddr,
3541 NULL, NULL );
sewardjb4112022007-11-09 22:49:28 +00003542 }
3543 }
3544
3545 /* Second, add to laog the pairs
3546 (old, lk) | old <- locks already held by thr
3547 Since both old and lk are currently held by thr, their acquired_at
3548 fields must be non-NULL.
3549 */
3550 tl_assert(lk->acquired_at);
3551 HG_(getPayloadWS)( &ls_words, &ls_size, univ_lsets, thr->locksetA );
3552 for (i = 0; i < ls_size; i++) {
3553 Lock* old = (Lock*)ls_words[i];
3554 tl_assert(old->acquired_at);
3555 laog__add_edge( old, lk );
3556 }
3557
3558 /* Why "except_Locks" ? We're here because a lock is being
3559 acquired by a thread, and we're in an inconsistent state here.
3560 See the call points in evhH__post_thread_{r,w}_acquires_lock.
3561 When called in this inconsistent state, locks__sanity_check duly
3562 barfs. */
sewardjf98e1c02008-10-25 16:22:41 +00003563 if (HG_(clo_sanity_flags) & SCE_LAOG)
sewardjb4112022007-11-09 22:49:28 +00003564 all_except_Locks__sanity_check("laog__pre_thread_acquires_lock-post");
3565}
3566
3567
3568/* Delete from 'laog' any pair mentioning a lock in locksToDelete */
3569
3570__attribute__((noinline))
3571static void laog__handle_one_lock_deletion ( Lock* lk )
3572{
3573 WordSetID preds, succs;
3574 Word preds_size, succs_size, i, j;
sewardj250ec2e2008-02-15 22:02:30 +00003575 UWord *preds_words, *succs_words;
sewardjb4112022007-11-09 22:49:28 +00003576
3577 preds = laog__preds( lk );
3578 succs = laog__succs( lk );
3579
3580 HG_(getPayloadWS)( &preds_words, &preds_size, univ_laog, preds );
3581 for (i = 0; i < preds_size; i++)
3582 laog__del_edge( (Lock*)preds_words[i], lk );
3583
3584 HG_(getPayloadWS)( &succs_words, &succs_size, univ_laog, succs );
3585 for (j = 0; j < succs_size; j++)
3586 laog__del_edge( lk, (Lock*)succs_words[j] );
3587
3588 for (i = 0; i < preds_size; i++) {
3589 for (j = 0; j < succs_size; j++) {
3590 if (preds_words[i] != succs_words[j]) {
3591 /* This can pass unlocked locks to laog__add_edge, since
3592 we're deleting stuff. So their acquired_at fields may
3593 be NULL. */
3594 laog__add_edge( (Lock*)preds_words[i], (Lock*)succs_words[j] );
3595 }
3596 }
3597 }
3598}
3599
sewardj1cbc12f2008-11-10 16:16:46 +00003600//__attribute__((noinline))
3601//static void laog__handle_lock_deletions (
3602// WordSetID /* in univ_laog */ locksToDelete
3603// )
3604//{
3605// Word i, ws_size;
3606// UWord* ws_words;
3607//
sewardj1cbc12f2008-11-10 16:16:46 +00003608//
3609// HG_(getPayloadWS)( &ws_words, &ws_size, univ_lsets, locksToDelete );
3610// for (i = 0; i < ws_size; i++)
3611// laog__handle_one_lock_deletion( (Lock*)ws_words[i] );
3612//
3613// if (HG_(clo_sanity_flags) & SCE_LAOG)
3614// all__sanity_check("laog__handle_lock_deletions-post");
3615//}
sewardjb4112022007-11-09 22:49:28 +00003616
3617
3618/*--------------------------------------------------------------*/
3619/*--- Malloc/free replacements ---*/
3620/*--------------------------------------------------------------*/
3621
3622typedef
3623 struct {
3624 void* next; /* required by m_hashtable */
3625 Addr payload; /* ptr to actual block */
3626 SizeT szB; /* size requested */
3627 ExeContext* where; /* where it was allocated */
3628 Thread* thr; /* allocating thread */
3629 }
3630 MallocMeta;
3631
3632/* A hash table of MallocMetas, used to track malloc'd blocks
3633 (obviously). */
3634static VgHashTable hg_mallocmeta_table = NULL;
3635
3636
3637static MallocMeta* new_MallocMeta ( void ) {
sewardjf98e1c02008-10-25 16:22:41 +00003638 MallocMeta* md = HG_(zalloc)( "hg.new_MallocMeta.1", sizeof(MallocMeta) );
sewardjb4112022007-11-09 22:49:28 +00003639 tl_assert(md);
3640 return md;
3641}
3642static void delete_MallocMeta ( MallocMeta* md ) {
sewardjf98e1c02008-10-25 16:22:41 +00003643 HG_(free)(md);
sewardjb4112022007-11-09 22:49:28 +00003644}
3645
3646
3647/* Allocate a client block and set up the metadata for it. */
3648
3649static
3650void* handle_alloc ( ThreadId tid,
3651 SizeT szB, SizeT alignB, Bool is_zeroed )
3652{
3653 Addr p;
3654 MallocMeta* md;
3655
3656 tl_assert( ((SSizeT)szB) >= 0 );
3657 p = (Addr)VG_(cli_malloc)(alignB, szB);
3658 if (!p) {
3659 return NULL;
3660 }
3661 if (is_zeroed)
3662 VG_(memset)((void*)p, 0, szB);
3663
3664 /* Note that map_threads_lookup must succeed (cannot assert), since
3665 memory can only be allocated by currently alive threads, hence
3666 they must have an entry in map_threads. */
3667 md = new_MallocMeta();
3668 md->payload = p;
3669 md->szB = szB;
3670 md->where = VG_(record_ExeContext)( tid, 0 );
3671 md->thr = map_threads_lookup( tid );
3672
3673 VG_(HT_add_node)( hg_mallocmeta_table, (VgHashNode*)md );
3674
3675 /* Tell the lower level memory wranglers. */
3676 evh__new_mem_heap( p, szB, is_zeroed );
3677
3678 return (void*)p;
3679}
3680
3681/* Re the checks for less-than-zero (also in hg_cli__realloc below):
3682 Cast to a signed type to catch any unexpectedly negative args.
3683 We're assuming here that the size asked for is not greater than
3684 2^31 bytes (for 32-bit platforms) or 2^63 bytes (for 64-bit
3685 platforms). */
3686static void* hg_cli__malloc ( ThreadId tid, SizeT n ) {
3687 if (((SSizeT)n) < 0) return NULL;
3688 return handle_alloc ( tid, n, VG_(clo_alignment),
3689 /*is_zeroed*/False );
3690}
3691static void* hg_cli____builtin_new ( ThreadId tid, SizeT n ) {
3692 if (((SSizeT)n) < 0) return NULL;
3693 return handle_alloc ( tid, n, VG_(clo_alignment),
3694 /*is_zeroed*/False );
3695}
3696static void* hg_cli____builtin_vec_new ( ThreadId tid, SizeT n ) {
3697 if (((SSizeT)n) < 0) return NULL;
3698 return handle_alloc ( tid, n, VG_(clo_alignment),
3699 /*is_zeroed*/False );
3700}
3701static void* hg_cli__memalign ( ThreadId tid, SizeT align, SizeT n ) {
3702 if (((SSizeT)n) < 0) return NULL;
3703 return handle_alloc ( tid, n, align,
3704 /*is_zeroed*/False );
3705}
3706static void* hg_cli__calloc ( ThreadId tid, SizeT nmemb, SizeT size1 ) {
3707 if ( ((SSizeT)nmemb) < 0 || ((SSizeT)size1) < 0 ) return NULL;
3708 return handle_alloc ( tid, nmemb*size1, VG_(clo_alignment),
3709 /*is_zeroed*/True );
3710}
3711
3712
3713/* Free a client block, including getting rid of the relevant
3714 metadata. */
3715
3716static void handle_free ( ThreadId tid, void* p )
3717{
3718 MallocMeta *md, *old_md;
3719 SizeT szB;
3720
3721 /* First see if we can find the metadata for 'p'. */
3722 md = (MallocMeta*) VG_(HT_lookup)( hg_mallocmeta_table, (UWord)p );
3723 if (!md)
3724 return; /* apparently freeing a bogus address. Oh well. */
3725
3726 tl_assert(md->payload == (Addr)p);
3727 szB = md->szB;
3728
3729 /* Nuke the metadata block */
3730 old_md = (MallocMeta*)
3731 VG_(HT_remove)( hg_mallocmeta_table, (UWord)p );
3732 tl_assert(old_md); /* it must be present - we just found it */
3733 tl_assert(old_md == md);
3734 tl_assert(old_md->payload == (Addr)p);
3735
3736 VG_(cli_free)((void*)old_md->payload);
3737 delete_MallocMeta(old_md);
3738
3739 /* Tell the lower level memory wranglers. */
3740 evh__die_mem_heap( (Addr)p, szB );
3741}
3742
3743static void hg_cli__free ( ThreadId tid, void* p ) {
3744 handle_free(tid, p);
3745}
3746static void hg_cli____builtin_delete ( ThreadId tid, void* p ) {
3747 handle_free(tid, p);
3748}
3749static void hg_cli____builtin_vec_delete ( ThreadId tid, void* p ) {
3750 handle_free(tid, p);
3751}
3752
3753
3754static void* hg_cli__realloc ( ThreadId tid, void* payloadV, SizeT new_size )
3755{
3756 MallocMeta *md, *md_new, *md_tmp;
3757 SizeT i;
3758
3759 Addr payload = (Addr)payloadV;
3760
3761 if (((SSizeT)new_size) < 0) return NULL;
3762
3763 md = (MallocMeta*) VG_(HT_lookup)( hg_mallocmeta_table, (UWord)payload );
3764 if (!md)
3765 return NULL; /* apparently realloc-ing a bogus address. Oh well. */
3766
3767 tl_assert(md->payload == payload);
3768
3769 if (md->szB == new_size) {
3770 /* size unchanged */
3771 md->where = VG_(record_ExeContext)(tid, 0);
3772 return payloadV;
3773 }
3774
3775 if (md->szB > new_size) {
3776 /* new size is smaller */
3777 md->szB = new_size;
3778 md->where = VG_(record_ExeContext)(tid, 0);
3779 evh__die_mem_heap( md->payload + new_size, md->szB - new_size );
3780 return payloadV;
3781 }
3782
3783 /* else */ {
3784 /* new size is bigger */
3785 Addr p_new = (Addr)VG_(cli_malloc)(VG_(clo_alignment), new_size);
3786
3787 /* First half kept and copied, second half new */
3788 // FIXME: shouldn't we use a copier which implements the
3789 // memory state machine?
sewardj23f12002009-07-24 08:45:08 +00003790 evh__copy_mem( payload, p_new, md->szB );
sewardjb4112022007-11-09 22:49:28 +00003791 evh__new_mem_heap ( p_new + md->szB, new_size - md->szB,
sewardjf98e1c02008-10-25 16:22:41 +00003792 /*inited*/False );
sewardjb4112022007-11-09 22:49:28 +00003793 /* FIXME: can anything funny happen here? specifically, if the
3794 old range contained a lock, then die_mem_heap will complain.
3795 Is that the correct behaviour? Not sure. */
3796 evh__die_mem_heap( payload, md->szB );
3797
3798 /* Copy from old to new */
3799 for (i = 0; i < md->szB; i++)
3800 ((UChar*)p_new)[i] = ((UChar*)payload)[i];
3801
3802 /* Because the metadata hash table is index by payload address,
3803 we have to get rid of the old hash table entry and make a new
3804 one. We can't just modify the existing metadata in place,
3805 because then it would (almost certainly) be in the wrong hash
3806 chain. */
3807 md_new = new_MallocMeta();
3808 *md_new = *md;
3809
3810 md_tmp = VG_(HT_remove)( hg_mallocmeta_table, payload );
3811 tl_assert(md_tmp);
3812 tl_assert(md_tmp == md);
3813
3814 VG_(cli_free)((void*)md->payload);
3815 delete_MallocMeta(md);
3816
3817 /* Update fields */
3818 md_new->where = VG_(record_ExeContext)( tid, 0 );
3819 md_new->szB = new_size;
3820 md_new->payload = p_new;
3821 md_new->thr = map_threads_lookup( tid );
3822
3823 /* and add */
3824 VG_(HT_add_node)( hg_mallocmeta_table, (VgHashNode*)md_new );
3825
3826 return (void*)p_new;
3827 }
3828}
3829
njn8b140de2009-02-17 04:31:18 +00003830static SizeT hg_cli_malloc_usable_size ( ThreadId tid, void* p )
3831{
3832 MallocMeta *md = VG_(HT_lookup)( hg_mallocmeta_table, (UWord)p );
3833
3834 // There may be slop, but pretend there isn't because only the asked-for
3835 // area will have been shadowed properly.
3836 return ( md ? md->szB : 0 );
3837}
3838
sewardjb4112022007-11-09 22:49:28 +00003839
sewardj095d61e2010-03-11 13:43:18 +00003840/* For error creation: map 'data_addr' to a malloc'd chunk, if any.
sewardjc8028ad2010-05-05 09:34:42 +00003841 Slow linear search. With a bit of hash table help if 'data_addr'
3842 is either the start of a block or up to 15 word-sized steps along
3843 from the start of a block. */
sewardj095d61e2010-03-11 13:43:18 +00003844
3845static inline Bool addr_is_in_MM_Chunk( MallocMeta* mm, Addr a )
3846{
sewardjc8028ad2010-05-05 09:34:42 +00003847 /* Accept 'a' as within 'mm' if 'mm's size is zero and 'a' points
3848 right at it. */
3849 if (UNLIKELY(mm->szB == 0 && a == mm->payload))
3850 return True;
3851 /* else normal interval rules apply */
3852 if (LIKELY(a < mm->payload)) return False;
3853 if (LIKELY(a >= mm->payload + mm->szB)) return False;
3854 return True;
sewardj095d61e2010-03-11 13:43:18 +00003855}
3856
sewardjc8028ad2010-05-05 09:34:42 +00003857Bool HG_(mm_find_containing_block)( /*OUT*/ExeContext** where,
sewardj095d61e2010-03-11 13:43:18 +00003858 /*OUT*/Addr* payload,
3859 /*OUT*/SizeT* szB,
3860 Addr data_addr )
3861{
3862 MallocMeta* mm;
sewardjc8028ad2010-05-05 09:34:42 +00003863 Int i;
3864 const Int n_fast_check_words = 16;
3865
3866 /* First, do a few fast searches on the basis that data_addr might
3867 be exactly the start of a block or up to 15 words inside. This
3868 can happen commonly via the creq
3869 _VG_USERREQ__HG_CLEAN_MEMORY_HEAPBLOCK. */
3870 for (i = 0; i < n_fast_check_words; i++) {
3871 mm = VG_(HT_lookup)( hg_mallocmeta_table,
3872 data_addr - (UWord)(UInt)i * sizeof(UWord) );
3873 if (UNLIKELY(mm && addr_is_in_MM_Chunk(mm, data_addr)))
3874 goto found;
3875 }
3876
sewardj095d61e2010-03-11 13:43:18 +00003877 /* Well, this totally sucks. But without using an interval tree or
sewardjc8028ad2010-05-05 09:34:42 +00003878 some such, it's hard to see how to do better. We have to check
3879 every block in the entire table. */
sewardj095d61e2010-03-11 13:43:18 +00003880 VG_(HT_ResetIter)(hg_mallocmeta_table);
3881 while ( (mm = VG_(HT_Next)(hg_mallocmeta_table)) ) {
sewardjc8028ad2010-05-05 09:34:42 +00003882 if (UNLIKELY(addr_is_in_MM_Chunk(mm, data_addr)))
3883 goto found;
sewardj095d61e2010-03-11 13:43:18 +00003884 }
sewardjc8028ad2010-05-05 09:34:42 +00003885
3886 /* Not found. Bah. */
3887 return False;
3888 /*NOTREACHED*/
3889
3890 found:
3891 tl_assert(mm);
3892 tl_assert(addr_is_in_MM_Chunk(mm, data_addr));
3893 if (where) *where = mm->where;
3894 if (payload) *payload = mm->payload;
3895 if (szB) *szB = mm->szB;
3896 return True;
sewardj095d61e2010-03-11 13:43:18 +00003897}
3898
3899
sewardjb4112022007-11-09 22:49:28 +00003900/*--------------------------------------------------------------*/
3901/*--- Instrumentation ---*/
3902/*--------------------------------------------------------------*/
3903
3904static void instrument_mem_access ( IRSB* bbOut,
3905 IRExpr* addr,
3906 Int szB,
3907 Bool isStore,
3908 Int hWordTy_szB )
3909{
3910 IRType tyAddr = Ity_INVALID;
3911 HChar* hName = NULL;
3912 void* hAddr = NULL;
3913 Int regparms = 0;
3914 IRExpr** argv = NULL;
3915 IRDirty* di = NULL;
3916
3917 tl_assert(isIRAtom(addr));
3918 tl_assert(hWordTy_szB == 4 || hWordTy_szB == 8);
3919
3920 tyAddr = typeOfIRExpr( bbOut->tyenv, addr );
3921 tl_assert(tyAddr == Ity_I32 || tyAddr == Ity_I64);
3922
3923 /* So the effective address is in 'addr' now. */
3924 regparms = 1; // unless stated otherwise
3925 if (isStore) {
3926 switch (szB) {
3927 case 1:
sewardj23f12002009-07-24 08:45:08 +00003928 hName = "evh__mem_help_cwrite_1";
3929 hAddr = &evh__mem_help_cwrite_1;
sewardjb4112022007-11-09 22:49:28 +00003930 argv = mkIRExprVec_1( addr );
3931 break;
3932 case 2:
sewardj23f12002009-07-24 08:45:08 +00003933 hName = "evh__mem_help_cwrite_2";
3934 hAddr = &evh__mem_help_cwrite_2;
sewardjb4112022007-11-09 22:49:28 +00003935 argv = mkIRExprVec_1( addr );
3936 break;
3937 case 4:
sewardj23f12002009-07-24 08:45:08 +00003938 hName = "evh__mem_help_cwrite_4";
3939 hAddr = &evh__mem_help_cwrite_4;
sewardjb4112022007-11-09 22:49:28 +00003940 argv = mkIRExprVec_1( addr );
3941 break;
3942 case 8:
sewardj23f12002009-07-24 08:45:08 +00003943 hName = "evh__mem_help_cwrite_8";
3944 hAddr = &evh__mem_help_cwrite_8;
sewardjb4112022007-11-09 22:49:28 +00003945 argv = mkIRExprVec_1( addr );
3946 break;
3947 default:
3948 tl_assert(szB > 8 && szB <= 512); /* stay sane */
3949 regparms = 2;
sewardj23f12002009-07-24 08:45:08 +00003950 hName = "evh__mem_help_cwrite_N";
3951 hAddr = &evh__mem_help_cwrite_N;
sewardjb4112022007-11-09 22:49:28 +00003952 argv = mkIRExprVec_2( addr, mkIRExpr_HWord( szB ));
3953 break;
3954 }
3955 } else {
3956 switch (szB) {
3957 case 1:
sewardj23f12002009-07-24 08:45:08 +00003958 hName = "evh__mem_help_cread_1";
3959 hAddr = &evh__mem_help_cread_1;
sewardjb4112022007-11-09 22:49:28 +00003960 argv = mkIRExprVec_1( addr );
3961 break;
3962 case 2:
sewardj23f12002009-07-24 08:45:08 +00003963 hName = "evh__mem_help_cread_2";
3964 hAddr = &evh__mem_help_cread_2;
sewardjb4112022007-11-09 22:49:28 +00003965 argv = mkIRExprVec_1( addr );
3966 break;
3967 case 4:
sewardj23f12002009-07-24 08:45:08 +00003968 hName = "evh__mem_help_cread_4";
3969 hAddr = &evh__mem_help_cread_4;
sewardjb4112022007-11-09 22:49:28 +00003970 argv = mkIRExprVec_1( addr );
3971 break;
3972 case 8:
sewardj23f12002009-07-24 08:45:08 +00003973 hName = "evh__mem_help_cread_8";
3974 hAddr = &evh__mem_help_cread_8;
sewardjb4112022007-11-09 22:49:28 +00003975 argv = mkIRExprVec_1( addr );
3976 break;
3977 default:
3978 tl_assert(szB > 8 && szB <= 512); /* stay sane */
3979 regparms = 2;
sewardj23f12002009-07-24 08:45:08 +00003980 hName = "evh__mem_help_cread_N";
3981 hAddr = &evh__mem_help_cread_N;
sewardjb4112022007-11-09 22:49:28 +00003982 argv = mkIRExprVec_2( addr, mkIRExpr_HWord( szB ));
3983 break;
3984 }
3985 }
3986
3987 /* Add the helper. */
3988 tl_assert(hName);
3989 tl_assert(hAddr);
3990 tl_assert(argv);
3991 di = unsafeIRDirty_0_N( regparms,
3992 hName, VG_(fnptr_to_fnentry)( hAddr ),
3993 argv );
3994 addStmtToIRSB( bbOut, IRStmt_Dirty(di) );
3995}
3996
3997
sewardja0eee322009-07-31 08:46:35 +00003998/* Figure out if GA is a guest code address in the dynamic linker, and
3999 if so return True. Otherwise (and in case of any doubt) return
4000 False. (sidedly safe w/ False as the safe value) */
4001static Bool is_in_dynamic_linker_shared_object( Addr64 ga )
4002{
4003 DebugInfo* dinfo;
4004 const UChar* soname;
4005 if (0) return False;
4006
sewardje3f1e592009-07-31 09:41:29 +00004007 dinfo = VG_(find_DebugInfo)( (Addr)ga );
sewardja0eee322009-07-31 08:46:35 +00004008 if (!dinfo) return False;
4009
sewardje3f1e592009-07-31 09:41:29 +00004010 soname = VG_(DebugInfo_get_soname)(dinfo);
sewardja0eee322009-07-31 08:46:35 +00004011 tl_assert(soname);
4012 if (0) VG_(printf)("%s\n", soname);
4013
4014# if defined(VGO_linux)
sewardj651cfa42010-01-11 13:02:19 +00004015 if (VG_STREQ(soname, VG_U_LD_LINUX_SO_3)) return True;
sewardja0eee322009-07-31 08:46:35 +00004016 if (VG_STREQ(soname, VG_U_LD_LINUX_SO_2)) return True;
4017 if (VG_STREQ(soname, VG_U_LD_LINUX_X86_64_SO_2)) return True;
4018 if (VG_STREQ(soname, VG_U_LD64_SO_1)) return True;
4019 if (VG_STREQ(soname, VG_U_LD_SO_1)) return True;
4020# elif defined(VGO_darwin)
4021 if (VG_STREQ(soname, VG_U_DYLD)) return True;
4022# else
4023# error "Unsupported OS"
4024# endif
4025 return False;
4026}
4027
sewardjb4112022007-11-09 22:49:28 +00004028static
4029IRSB* hg_instrument ( VgCallbackClosure* closure,
4030 IRSB* bbIn,
4031 VexGuestLayout* layout,
4032 VexGuestExtents* vge,
4033 IRType gWordTy, IRType hWordTy )
4034{
sewardj1c0ce7a2009-07-01 08:10:49 +00004035 Int i;
4036 IRSB* bbOut;
4037 Addr64 cia; /* address of current insn */
4038 IRStmt* st;
sewardja0eee322009-07-31 08:46:35 +00004039 Bool inLDSO = False;
4040 Addr64 inLDSOmask4K = 1; /* mismatches on first check */
sewardjb4112022007-11-09 22:49:28 +00004041
4042 if (gWordTy != hWordTy) {
4043 /* We don't currently support this case. */
4044 VG_(tool_panic)("host/guest word size mismatch");
4045 }
4046
sewardja0eee322009-07-31 08:46:35 +00004047 if (VKI_PAGE_SIZE < 4096 || VG_(log2)(VKI_PAGE_SIZE) == -1) {
4048 VG_(tool_panic)("implausible or too-small VKI_PAGE_SIZE");
4049 }
4050
sewardjb4112022007-11-09 22:49:28 +00004051 /* Set up BB */
4052 bbOut = emptyIRSB();
4053 bbOut->tyenv = deepCopyIRTypeEnv(bbIn->tyenv);
4054 bbOut->next = deepCopyIRExpr(bbIn->next);
4055 bbOut->jumpkind = bbIn->jumpkind;
4056
4057 // Copy verbatim any IR preamble preceding the first IMark
4058 i = 0;
4059 while (i < bbIn->stmts_used && bbIn->stmts[i]->tag != Ist_IMark) {
4060 addStmtToIRSB( bbOut, bbIn->stmts[i] );
4061 i++;
4062 }
4063
sewardj1c0ce7a2009-07-01 08:10:49 +00004064 // Get the first statement, and initial cia from it
4065 tl_assert(bbIn->stmts_used > 0);
4066 tl_assert(i < bbIn->stmts_used);
4067 st = bbIn->stmts[i];
4068 tl_assert(Ist_IMark == st->tag);
4069 cia = st->Ist.IMark.addr;
4070 st = NULL;
4071
sewardjb4112022007-11-09 22:49:28 +00004072 for (/*use current i*/; i < bbIn->stmts_used; i++) {
sewardj1c0ce7a2009-07-01 08:10:49 +00004073 st = bbIn->stmts[i];
sewardjb4112022007-11-09 22:49:28 +00004074 tl_assert(st);
4075 tl_assert(isFlatIRStmt(st));
4076 switch (st->tag) {
4077 case Ist_NoOp:
4078 case Ist_AbiHint:
4079 case Ist_Put:
4080 case Ist_PutI:
sewardjb4112022007-11-09 22:49:28 +00004081 case Ist_Exit:
4082 /* None of these can contain any memory references. */
4083 break;
4084
sewardj1c0ce7a2009-07-01 08:10:49 +00004085 case Ist_IMark:
4086 /* no mem refs, but note the insn address. */
4087 cia = st->Ist.IMark.addr;
sewardja0eee322009-07-31 08:46:35 +00004088 /* Don't instrument the dynamic linker. It generates a
4089 lot of races which we just expensively suppress, so
4090 it's pointless.
4091
4092 Avoid flooding is_in_dynamic_linker_shared_object with
4093 requests by only checking at transitions between 4K
4094 pages. */
4095 if ((cia & ~(Addr64)0xFFF) != inLDSOmask4K) {
4096 if (0) VG_(printf)("NEW %#lx\n", (Addr)cia);
4097 inLDSOmask4K = cia & ~(Addr64)0xFFF;
4098 inLDSO = is_in_dynamic_linker_shared_object(cia);
4099 } else {
4100 if (0) VG_(printf)("old %#lx\n", (Addr)cia);
4101 }
sewardj1c0ce7a2009-07-01 08:10:49 +00004102 break;
4103
sewardjb4112022007-11-09 22:49:28 +00004104 case Ist_MBE:
sewardjf98e1c02008-10-25 16:22:41 +00004105 switch (st->Ist.MBE.event) {
4106 case Imbe_Fence:
4107 break; /* not interesting */
sewardjf98e1c02008-10-25 16:22:41 +00004108 default:
4109 goto unhandled;
4110 }
sewardjb4112022007-11-09 22:49:28 +00004111 break;
4112
sewardj1c0ce7a2009-07-01 08:10:49 +00004113 case Ist_CAS: {
4114 /* Atomic read-modify-write cycle. Just pretend it's a
4115 read. */
4116 IRCAS* cas = st->Ist.CAS.details;
sewardj23f12002009-07-24 08:45:08 +00004117 Bool isDCAS = cas->oldHi != IRTemp_INVALID;
4118 if (isDCAS) {
4119 tl_assert(cas->expdHi);
4120 tl_assert(cas->dataHi);
4121 } else {
4122 tl_assert(!cas->expdHi);
4123 tl_assert(!cas->dataHi);
4124 }
4125 /* Just be boring about it. */
sewardja0eee322009-07-31 08:46:35 +00004126 if (!inLDSO) {
4127 instrument_mem_access(
4128 bbOut,
4129 cas->addr,
4130 (isDCAS ? 2 : 1)
4131 * sizeofIRType(typeOfIRExpr(bbIn->tyenv, cas->dataLo)),
4132 False/*!isStore*/,
4133 sizeofIRType(hWordTy)
4134 );
4135 }
sewardj1c0ce7a2009-07-01 08:10:49 +00004136 break;
4137 }
4138
sewardjdb5907d2009-11-26 17:20:21 +00004139 case Ist_LLSC: {
4140 /* We pretend store-conditionals don't exist, viz, ignore
4141 them. Whereas load-linked's are treated the same as
4142 normal loads. */
4143 IRType dataTy;
4144 if (st->Ist.LLSC.storedata == NULL) {
4145 /* LL */
4146 dataTy = typeOfIRTemp(bbIn->tyenv, st->Ist.LLSC.result);
sewardja0eee322009-07-31 08:46:35 +00004147 if (!inLDSO) {
sewardjdb5907d2009-11-26 17:20:21 +00004148 instrument_mem_access(
4149 bbOut,
4150 st->Ist.LLSC.addr,
4151 sizeofIRType(dataTy),
4152 False/*!isStore*/,
sewardja0eee322009-07-31 08:46:35 +00004153 sizeofIRType(hWordTy)
4154 );
4155 }
sewardjdb5907d2009-11-26 17:20:21 +00004156 } else {
4157 /* SC */
4158 /*ignore */
4159 }
4160 break;
4161 }
4162
4163 case Ist_Store:
4164 /* It seems we pretend that store-conditionals don't
4165 exist, viz, just ignore them ... */
4166 if (!inLDSO) {
4167 instrument_mem_access(
4168 bbOut,
4169 st->Ist.Store.addr,
4170 sizeofIRType(typeOfIRExpr(bbIn->tyenv, st->Ist.Store.data)),
4171 True/*isStore*/,
4172 sizeofIRType(hWordTy)
4173 );
sewardj1c0ce7a2009-07-01 08:10:49 +00004174 }
njnb83caf22009-05-25 01:47:56 +00004175 break;
sewardjb4112022007-11-09 22:49:28 +00004176
4177 case Ist_WrTmp: {
sewardj1c0ce7a2009-07-01 08:10:49 +00004178 /* ... whereas here we don't care whether a load is a
4179 vanilla one or a load-linked. */
sewardjb4112022007-11-09 22:49:28 +00004180 IRExpr* data = st->Ist.WrTmp.data;
4181 if (data->tag == Iex_Load) {
sewardja0eee322009-07-31 08:46:35 +00004182 if (!inLDSO) {
4183 instrument_mem_access(
4184 bbOut,
4185 data->Iex.Load.addr,
4186 sizeofIRType(data->Iex.Load.ty),
4187 False/*!isStore*/,
4188 sizeofIRType(hWordTy)
4189 );
4190 }
sewardjb4112022007-11-09 22:49:28 +00004191 }
4192 break;
4193 }
4194
4195 case Ist_Dirty: {
4196 Int dataSize;
4197 IRDirty* d = st->Ist.Dirty.details;
4198 if (d->mFx != Ifx_None) {
4199 /* This dirty helper accesses memory. Collect the
4200 details. */
4201 tl_assert(d->mAddr != NULL);
4202 tl_assert(d->mSize != 0);
4203 dataSize = d->mSize;
4204 if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify) {
sewardja0eee322009-07-31 08:46:35 +00004205 if (!inLDSO) {
4206 instrument_mem_access(
4207 bbOut, d->mAddr, dataSize, False/*!isStore*/,
4208 sizeofIRType(hWordTy)
4209 );
4210 }
sewardjb4112022007-11-09 22:49:28 +00004211 }
4212 if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify) {
sewardja0eee322009-07-31 08:46:35 +00004213 if (!inLDSO) {
4214 instrument_mem_access(
4215 bbOut, d->mAddr, dataSize, True/*isStore*/,
4216 sizeofIRType(hWordTy)
4217 );
4218 }
sewardjb4112022007-11-09 22:49:28 +00004219 }
4220 } else {
4221 tl_assert(d->mAddr == NULL);
4222 tl_assert(d->mSize == 0);
4223 }
4224 break;
4225 }
4226
4227 default:
sewardjf98e1c02008-10-25 16:22:41 +00004228 unhandled:
4229 ppIRStmt(st);
sewardjb4112022007-11-09 22:49:28 +00004230 tl_assert(0);
4231
4232 } /* switch (st->tag) */
4233
4234 addStmtToIRSB( bbOut, st );
4235 } /* iterate over bbIn->stmts */
4236
4237 return bbOut;
4238}
4239
4240
4241/*----------------------------------------------------------------*/
4242/*--- Client requests ---*/
4243/*----------------------------------------------------------------*/
4244
4245/* Sheesh. Yet another goddam finite map. */
4246static WordFM* map_pthread_t_to_Thread = NULL; /* pthread_t -> Thread* */
4247
4248static void map_pthread_t_to_Thread_INIT ( void ) {
4249 if (UNLIKELY(map_pthread_t_to_Thread == NULL)) {
sewardjf98e1c02008-10-25 16:22:41 +00004250 map_pthread_t_to_Thread = VG_(newFM)( HG_(zalloc), "hg.mpttT.1",
4251 HG_(free), NULL );
sewardjb4112022007-11-09 22:49:28 +00004252 tl_assert(map_pthread_t_to_Thread != NULL);
4253 }
4254}
4255
4256
4257static
4258Bool hg_handle_client_request ( ThreadId tid, UWord* args, UWord* ret)
4259{
4260 if (!VG_IS_TOOL_USERREQ('H','G',args[0]))
4261 return False;
4262
4263 /* Anything that gets past the above check is one of ours, so we
4264 should be able to handle it. */
4265
4266 /* default, meaningless return value, unless otherwise set */
4267 *ret = 0;
4268
4269 switch (args[0]) {
4270
4271 /* --- --- User-visible client requests --- --- */
4272
4273 case VG_USERREQ__HG_CLEAN_MEMORY:
barta0b6b2c2008-07-07 06:49:24 +00004274 if (0) VG_(printf)("VG_USERREQ__HG_CLEAN_MEMORY(%#lx,%ld)\n",
sewardjb4112022007-11-09 22:49:28 +00004275 args[1], args[2]);
4276 /* Call die_mem to (expensively) tidy up properly, if there
sewardjf98e1c02008-10-25 16:22:41 +00004277 are any held locks etc in the area. Calling evh__die_mem
4278 and then evh__new_mem is a bit inefficient; probably just
4279 the latter would do. */
sewardjb4112022007-11-09 22:49:28 +00004280 if (args[2] > 0) { /* length */
4281 evh__die_mem(args[1], args[2]);
4282 /* and then set it to New */
4283 evh__new_mem(args[1], args[2]);
4284 }
4285 break;
4286
sewardjc8028ad2010-05-05 09:34:42 +00004287 case _VG_USERREQ__HG_CLEAN_MEMORY_HEAPBLOCK: {
4288 Addr payload = 0;
4289 SizeT pszB = 0;
4290 if (0) VG_(printf)("VG_USERREQ__HG_CLEAN_MEMORY_HEAPBLOCK(%#lx)\n",
4291 args[1]);
4292 if (HG_(mm_find_containing_block)(NULL, &payload, &pszB, args[1])) {
4293 if (pszB > 0) {
4294 evh__die_mem(payload, pszB);
4295 evh__new_mem(payload, pszB);
4296 }
4297 *ret = pszB;
4298 } else {
4299 *ret = (UWord)-1;
4300 }
4301 break;
4302 }
4303
sewardj406bac82010-03-03 23:03:40 +00004304 case _VG_USERREQ__HG_ARANGE_MAKE_UNTRACKED:
4305 if (0) VG_(printf)("HG_ARANGE_MAKE_UNTRACKED(%#lx,%ld)\n",
4306 args[1], args[2]);
4307 if (args[2] > 0) { /* length */
4308 evh__untrack_mem(args[1], args[2]);
4309 }
4310 break;
4311
4312 case _VG_USERREQ__HG_ARANGE_MAKE_TRACKED:
4313 if (0) VG_(printf)("HG_ARANGE_MAKE_TRACKED(%#lx,%ld)\n",
4314 args[1], args[2]);
4315 if (args[2] > 0) { /* length */
4316 evh__new_mem(args[1], args[2]);
4317 }
4318 break;
4319
sewardjb4112022007-11-09 22:49:28 +00004320 /* --- --- Client requests for Helgrind's use only --- --- */
4321
4322 /* Some thread is telling us its pthread_t value. Record the
4323 binding between that and the associated Thread*, so we can
4324 later find the Thread* again when notified of a join by the
4325 thread. */
4326 case _VG_USERREQ__HG_SET_MY_PTHREAD_T: {
4327 Thread* my_thr = NULL;
4328 if (0)
4329 VG_(printf)("SET_MY_PTHREAD_T (tid %d): pthread_t = %p\n", (Int)tid,
4330 (void*)args[1]);
4331 map_pthread_t_to_Thread_INIT();
4332 my_thr = map_threads_maybe_lookup( tid );
4333 /* This assertion should hold because the map_threads (tid to
4334 Thread*) binding should have been made at the point of
4335 low-level creation of this thread, which should have
4336 happened prior to us getting this client request for it.
4337 That's because this client request is sent from
4338 client-world from the 'thread_wrapper' function, which
4339 only runs once the thread has been low-level created. */
4340 tl_assert(my_thr != NULL);
4341 /* So now we know that (pthread_t)args[1] is associated with
4342 (Thread*)my_thr. Note that down. */
4343 if (0)
4344 VG_(printf)("XXXX: bind pthread_t %p to Thread* %p\n",
4345 (void*)args[1], (void*)my_thr );
sewardj896f6f92008-08-19 08:38:52 +00004346 VG_(addToFM)( map_pthread_t_to_Thread, (Word)args[1], (Word)my_thr );
sewardjb4112022007-11-09 22:49:28 +00004347 break;
4348 }
4349
4350 case _VG_USERREQ__HG_PTH_API_ERROR: {
4351 Thread* my_thr = NULL;
4352 map_pthread_t_to_Thread_INIT();
4353 my_thr = map_threads_maybe_lookup( tid );
4354 tl_assert(my_thr); /* See justification above in SET_MY_PTHREAD_T */
sewardjf98e1c02008-10-25 16:22:41 +00004355 HG_(record_error_PthAPIerror)(
4356 my_thr, (HChar*)args[1], (Word)args[2], (HChar*)args[3] );
sewardjb4112022007-11-09 22:49:28 +00004357 break;
4358 }
4359
4360 /* This thread (tid) has completed a join with the quitting
4361 thread whose pthread_t is in args[1]. */
4362 case _VG_USERREQ__HG_PTHREAD_JOIN_POST: {
4363 Thread* thr_q = NULL; /* quitter Thread* */
4364 Bool found = False;
4365 if (0)
4366 VG_(printf)("NOTIFY_JOIN_COMPLETE (tid %d): quitter = %p\n", (Int)tid,
4367 (void*)args[1]);
4368 map_pthread_t_to_Thread_INIT();
sewardj896f6f92008-08-19 08:38:52 +00004369 found = VG_(lookupFM)( map_pthread_t_to_Thread,
sewardjb5f29642007-11-16 12:02:43 +00004370 NULL, (Word*)&thr_q, (Word)args[1] );
sewardjb4112022007-11-09 22:49:28 +00004371 /* Can this fail? It would mean that our pthread_join
4372 wrapper observed a successful join on args[1] yet that
4373 thread never existed (or at least, it never lodged an
4374 entry in the mapping (via SET_MY_PTHREAD_T)). Which
4375 sounds like a bug in the threads library. */
4376 // FIXME: get rid of this assertion; handle properly
4377 tl_assert(found);
4378 if (found) {
4379 if (0)
4380 VG_(printf)(".................... quitter Thread* = %p\n",
4381 thr_q);
4382 evh__HG_PTHREAD_JOIN_POST( tid, thr_q );
4383 }
4384 break;
4385 }
4386
4387 /* EXPOSITION only: by intercepting lock init events we can show
4388 the user where the lock was initialised, rather than only
4389 being able to show where it was first locked. Intercepting
4390 lock initialisations is not necessary for the basic operation
4391 of the race checker. */
4392 case _VG_USERREQ__HG_PTHREAD_MUTEX_INIT_POST:
4393 evh__HG_PTHREAD_MUTEX_INIT_POST( tid, (void*)args[1], args[2] );
4394 break;
4395
4396 case _VG_USERREQ__HG_PTHREAD_MUTEX_DESTROY_PRE:
4397 evh__HG_PTHREAD_MUTEX_DESTROY_PRE( tid, (void*)args[1] );
4398 break;
4399
4400 case _VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_PRE: // pth_mx_t*
4401 evh__HG_PTHREAD_MUTEX_UNLOCK_PRE( tid, (void*)args[1] );
4402 break;
4403
4404 case _VG_USERREQ__HG_PTHREAD_MUTEX_UNLOCK_POST: // pth_mx_t*
4405 evh__HG_PTHREAD_MUTEX_UNLOCK_POST( tid, (void*)args[1] );
4406 break;
4407
4408 case _VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_PRE: // pth_mx_t*, Word
4409 evh__HG_PTHREAD_MUTEX_LOCK_PRE( tid, (void*)args[1], args[2] );
4410 break;
4411
4412 case _VG_USERREQ__HG_PTHREAD_MUTEX_LOCK_POST: // pth_mx_t*
4413 evh__HG_PTHREAD_MUTEX_LOCK_POST( tid, (void*)args[1] );
4414 break;
4415
4416 /* This thread is about to do pthread_cond_signal on the
4417 pthread_cond_t* in arg[1]. Ditto pthread_cond_broadcast. */
4418 case _VG_USERREQ__HG_PTHREAD_COND_SIGNAL_PRE:
4419 case _VG_USERREQ__HG_PTHREAD_COND_BROADCAST_PRE:
4420 evh__HG_PTHREAD_COND_SIGNAL_PRE( tid, (void*)args[1] );
4421 break;
4422
4423 /* Entry into pthread_cond_wait, cond=arg[1], mutex=arg[2].
4424 Returns a flag indicating whether or not the mutex is believed to be
4425 valid for this operation. */
4426 case _VG_USERREQ__HG_PTHREAD_COND_WAIT_PRE: {
4427 Bool mutex_is_valid
4428 = evh__HG_PTHREAD_COND_WAIT_PRE( tid, (void*)args[1],
4429 (void*)args[2] );
4430 *ret = mutex_is_valid ? 1 : 0;
4431 break;
4432 }
4433
sewardjf98e1c02008-10-25 16:22:41 +00004434 /* cond=arg[1] */
4435 case _VG_USERREQ__HG_PTHREAD_COND_DESTROY_PRE:
4436 evh__HG_PTHREAD_COND_DESTROY_PRE( tid, (void*)args[1] );
4437 break;
4438
sewardjb4112022007-11-09 22:49:28 +00004439 /* Thread successfully completed pthread_cond_wait, cond=arg[1],
4440 mutex=arg[2] */
4441 case _VG_USERREQ__HG_PTHREAD_COND_WAIT_POST:
4442 evh__HG_PTHREAD_COND_WAIT_POST( tid,
4443 (void*)args[1], (void*)args[2] );
4444 break;
4445
4446 case _VG_USERREQ__HG_PTHREAD_RWLOCK_INIT_POST:
4447 evh__HG_PTHREAD_RWLOCK_INIT_POST( tid, (void*)args[1] );
4448 break;
4449
4450 case _VG_USERREQ__HG_PTHREAD_RWLOCK_DESTROY_PRE:
4451 evh__HG_PTHREAD_RWLOCK_DESTROY_PRE( tid, (void*)args[1] );
4452 break;
4453
sewardj789c3c52008-02-25 12:10:07 +00004454 /* rwlock=arg[1], isW=arg[2], isTryLock=arg[3] */
sewardjb4112022007-11-09 22:49:28 +00004455 case _VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_PRE:
sewardj789c3c52008-02-25 12:10:07 +00004456 evh__HG_PTHREAD_RWLOCK_LOCK_PRE( tid, (void*)args[1],
4457 args[2], args[3] );
sewardjb4112022007-11-09 22:49:28 +00004458 break;
4459
4460 /* rwlock=arg[1], isW=arg[2] */
4461 case _VG_USERREQ__HG_PTHREAD_RWLOCK_LOCK_POST:
4462 evh__HG_PTHREAD_RWLOCK_LOCK_POST( tid, (void*)args[1], args[2] );
4463 break;
4464
4465 case _VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_PRE:
4466 evh__HG_PTHREAD_RWLOCK_UNLOCK_PRE( tid, (void*)args[1] );
4467 break;
4468
4469 case _VG_USERREQ__HG_PTHREAD_RWLOCK_UNLOCK_POST:
4470 evh__HG_PTHREAD_RWLOCK_UNLOCK_POST( tid, (void*)args[1] );
4471 break;
4472
sewardj11e352f2007-11-30 11:11:02 +00004473 case _VG_USERREQ__HG_POSIX_SEM_INIT_POST: /* sem_t*, unsigned long */
4474 evh__HG_POSIX_SEM_INIT_POST( tid, (void*)args[1], args[2] );
sewardjb4112022007-11-09 22:49:28 +00004475 break;
4476
sewardj11e352f2007-11-30 11:11:02 +00004477 case _VG_USERREQ__HG_POSIX_SEM_DESTROY_PRE: /* sem_t* */
4478 evh__HG_POSIX_SEM_DESTROY_PRE( tid, (void*)args[1] );
sewardjb4112022007-11-09 22:49:28 +00004479 break;
4480
sewardj11e352f2007-11-30 11:11:02 +00004481 case _VG_USERREQ__HG_POSIX_SEM_POST_PRE: /* sem_t* */
4482 evh__HG_POSIX_SEM_POST_PRE( tid, (void*)args[1] );
4483 break;
4484
4485 case _VG_USERREQ__HG_POSIX_SEM_WAIT_POST: /* sem_t* */
4486 evh__HG_POSIX_SEM_WAIT_POST( tid, (void*)args[1] );
sewardjb4112022007-11-09 22:49:28 +00004487 break;
4488
sewardj9f569b72008-11-13 13:33:09 +00004489 case _VG_USERREQ__HG_PTHREAD_BARRIER_INIT_PRE:
sewardj406bac82010-03-03 23:03:40 +00004490 /* pth_bar_t*, ulong count, ulong resizable */
4491 evh__HG_PTHREAD_BARRIER_INIT_PRE( tid, (void*)args[1],
4492 args[2], args[3] );
4493 break;
4494
4495 case _VG_USERREQ__HG_PTHREAD_BARRIER_RESIZE_PRE:
4496 /* pth_bar_t*, ulong newcount */
4497 evh__HG_PTHREAD_BARRIER_RESIZE_PRE ( tid, (void*)args[1],
4498 args[2] );
sewardj9f569b72008-11-13 13:33:09 +00004499 break;
4500
4501 case _VG_USERREQ__HG_PTHREAD_BARRIER_WAIT_PRE:
4502 /* pth_bar_t* */
4503 evh__HG_PTHREAD_BARRIER_WAIT_PRE( tid, (void*)args[1] );
4504 break;
4505
4506 case _VG_USERREQ__HG_PTHREAD_BARRIER_DESTROY_PRE:
4507 /* pth_bar_t* */
4508 evh__HG_PTHREAD_BARRIER_DESTROY_PRE( tid, (void*)args[1] );
4509 break;
sewardjb4112022007-11-09 22:49:28 +00004510
sewardj5a644da2009-08-11 10:35:58 +00004511 case _VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE:
4512 /* pth_spinlock_t* */
4513 evh__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_PRE( tid, (void*)args[1] );
4514 break;
4515
4516 case _VG_USERREQ__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST:
4517 /* pth_spinlock_t* */
4518 evh__HG_PTHREAD_SPIN_INIT_OR_UNLOCK_POST( tid, (void*)args[1] );
4519 break;
4520
4521 case _VG_USERREQ__HG_PTHREAD_SPIN_LOCK_PRE:
4522 /* pth_spinlock_t*, Word */
4523 evh__HG_PTHREAD_SPIN_LOCK_PRE( tid, (void*)args[1], args[2] );
4524 break;
4525
4526 case _VG_USERREQ__HG_PTHREAD_SPIN_LOCK_POST:
4527 /* pth_spinlock_t* */
4528 evh__HG_PTHREAD_SPIN_LOCK_POST( tid, (void*)args[1] );
4529 break;
4530
4531 case _VG_USERREQ__HG_PTHREAD_SPIN_DESTROY_PRE:
4532 /* pth_spinlock_t* */
4533 evh__HG_PTHREAD_SPIN_DESTROY_PRE( tid, (void*)args[1] );
4534 break;
4535
sewardjed2e72e2009-08-14 11:08:24 +00004536 case _VG_USERREQ__HG_CLIENTREQ_UNIMP: {
4537 /* char* who */
4538 HChar* who = (HChar*)args[1];
4539 HChar buf[50 + 50];
4540 Thread* thr = map_threads_maybe_lookup( tid );
4541 tl_assert( thr ); /* I must be mapped */
4542 tl_assert( who );
4543 tl_assert( VG_(strlen)(who) <= 50 );
4544 VG_(sprintf)(buf, "Unimplemented client request macro \"%s\"", who );
4545 /* record_error_Misc strdup's buf, so this is safe: */
4546 HG_(record_error_Misc)( thr, buf );
4547 break;
4548 }
4549
4550 case _VG_USERREQ__HG_USERSO_SEND_PRE:
4551 /* UWord arbitrary-SO-tag */
4552 evh__HG_USERSO_SEND_PRE( tid, args[1] );
4553 break;
4554
4555 case _VG_USERREQ__HG_USERSO_RECV_POST:
4556 /* UWord arbitrary-SO-tag */
4557 evh__HG_USERSO_RECV_POST( tid, args[1] );
4558 break;
4559
sewardj6015d0e2011-03-11 19:10:48 +00004560 case _VG_USERREQ__HG_USERSO_FORGET_ALL:
4561 /* UWord arbitrary-SO-tag */
4562 evh__HG_USERSO_FORGET_ALL( tid, args[1] );
4563 break;
4564
sewardjb4112022007-11-09 22:49:28 +00004565 default:
4566 /* Unhandled Helgrind client request! */
sewardjf98e1c02008-10-25 16:22:41 +00004567 tl_assert2(0, "unhandled Helgrind client request 0x%lx",
4568 args[0]);
sewardjb4112022007-11-09 22:49:28 +00004569 }
4570
4571 return True;
4572}
4573
4574
4575/*----------------------------------------------------------------*/
sewardjb4112022007-11-09 22:49:28 +00004576/*--- Setup ---*/
4577/*----------------------------------------------------------------*/
4578
4579static Bool hg_process_cmd_line_option ( Char* arg )
4580{
njn83df0b62009-02-25 01:01:05 +00004581 Char* tmp_str;
sewardjb4112022007-11-09 22:49:28 +00004582
njn83df0b62009-02-25 01:01:05 +00004583 if VG_BOOL_CLO(arg, "--track-lockorders",
4584 HG_(clo_track_lockorders)) {}
4585 else if VG_BOOL_CLO(arg, "--cmp-race-err-addrs",
4586 HG_(clo_cmp_race_err_addrs)) {}
sewardj23f12002009-07-24 08:45:08 +00004587
4588 else if VG_XACT_CLO(arg, "--history-level=none",
4589 HG_(clo_history_level), 0);
sewardjf3861392009-08-02 10:16:03 +00004590 else if VG_XACT_CLO(arg, "--history-level=approx",
sewardj23f12002009-07-24 08:45:08 +00004591 HG_(clo_history_level), 1);
4592 else if VG_XACT_CLO(arg, "--history-level=full",
4593 HG_(clo_history_level), 2);
sewardj849b0ed2008-12-21 10:43:10 +00004594
sewardjf585e482009-08-16 22:52:29 +00004595 /* If you change the 10k/30mill limits, remember to also change
sewardj849b0ed2008-12-21 10:43:10 +00004596 them in assertions at the top of event_map_maybe_GC. */
njn83df0b62009-02-25 01:01:05 +00004597 else if VG_BINT_CLO(arg, "--conflict-cache-size",
sewardjf585e482009-08-16 22:52:29 +00004598 HG_(clo_conflict_cache_size), 10*1000, 30*1000*1000) {}
sewardjb4112022007-11-09 22:49:28 +00004599
sewardj11e352f2007-11-30 11:11:02 +00004600 /* "stuvwx" --> stuvwx (binary) */
njn83df0b62009-02-25 01:01:05 +00004601 else if VG_STR_CLO(arg, "--hg-sanity-flags", tmp_str) {
sewardjb4112022007-11-09 22:49:28 +00004602 Int j;
sewardjb4112022007-11-09 22:49:28 +00004603
njn83df0b62009-02-25 01:01:05 +00004604 if (6 != VG_(strlen)(tmp_str)) {
sewardjb4112022007-11-09 22:49:28 +00004605 VG_(message)(Vg_UserMsg,
sewardj24118492009-07-15 14:50:02 +00004606 "--hg-sanity-flags argument must have 6 digits\n");
sewardjb4112022007-11-09 22:49:28 +00004607 return False;
4608 }
sewardj11e352f2007-11-30 11:11:02 +00004609 for (j = 0; j < 6; j++) {
njn83df0b62009-02-25 01:01:05 +00004610 if ('0' == tmp_str[j]) { /* do nothing */ }
4611 else if ('1' == tmp_str[j]) HG_(clo_sanity_flags) |= (1 << (6-1-j));
sewardjb4112022007-11-09 22:49:28 +00004612 else {
sewardj11e352f2007-11-30 11:11:02 +00004613 VG_(message)(Vg_UserMsg, "--hg-sanity-flags argument can "
sewardj24118492009-07-15 14:50:02 +00004614 "only contain 0s and 1s\n");
sewardjb4112022007-11-09 22:49:28 +00004615 return False;
4616 }
4617 }
sewardjf98e1c02008-10-25 16:22:41 +00004618 if (0) VG_(printf)("XXX sanity flags: 0x%lx\n", HG_(clo_sanity_flags));
sewardjb4112022007-11-09 22:49:28 +00004619 }
4620
sewardj622fe492011-03-11 21:06:59 +00004621 else if VG_BOOL_CLO(arg, "--free-is-write",
4622 HG_(clo_free_is_write)) {}
sewardjb4112022007-11-09 22:49:28 +00004623 else
4624 return VG_(replacement_malloc_process_cmd_line_option)(arg);
4625
4626 return True;
4627}
4628
4629static void hg_print_usage ( void )
4630{
4631 VG_(printf)(
sewardj622fe492011-03-11 21:06:59 +00004632" --free-is-write=no|yes treat heap frees as writes [no]\n"
sewardj849b0ed2008-12-21 10:43:10 +00004633" --track-lockorders=no|yes show lock ordering errors? [yes]\n"
njnf6e8ca92009-08-07 02:18:00 +00004634" --history-level=none|approx|full [full]\n"
sewardjf3861392009-08-02 10:16:03 +00004635" full: show both stack traces for a data race (can be very slow)\n"
4636" approx: full trace for one thread, approx for the other (faster)\n"
4637" none: only show trace for one thread in a race (fastest)\n"
sewardj23f12002009-07-24 08:45:08 +00004638" --conflict-cache-size=N size of 'full' history cache [1000000]\n"
sewardjb4112022007-11-09 22:49:28 +00004639 );
sewardjb4112022007-11-09 22:49:28 +00004640}
4641
4642static void hg_print_debug_usage ( void )
4643{
sewardjb4112022007-11-09 22:49:28 +00004644 VG_(printf)(" --cmp-race-err-addrs=no|yes are data addresses in "
4645 "race errors significant? [no]\n");
sewardj849b0ed2008-12-21 10:43:10 +00004646 VG_(printf)(" --hg-sanity-flags=<XXXXXX> sanity check "
sewardj11e352f2007-11-30 11:11:02 +00004647 " at events (X = 0|1) [000000]\n");
4648 VG_(printf)(" --hg-sanity-flags values:\n");
sewardj11e352f2007-11-30 11:11:02 +00004649 VG_(printf)(" 010000 after changes to "
sewardjb4112022007-11-09 22:49:28 +00004650 "lock-order-acquisition-graph\n");
sewardj11e352f2007-11-30 11:11:02 +00004651 VG_(printf)(" 001000 at memory accesses (NB: not currently used)\n");
4652 VG_(printf)(" 000100 at mem permission setting for "
sewardjb4112022007-11-09 22:49:28 +00004653 "ranges >= %d bytes\n", SCE_BIGRANGE_T);
sewardj11e352f2007-11-30 11:11:02 +00004654 VG_(printf)(" 000010 at lock/unlock events\n");
4655 VG_(printf)(" 000001 at thread create/join events\n");
sewardjb4112022007-11-09 22:49:28 +00004656}
4657
sewardjb4112022007-11-09 22:49:28 +00004658static void hg_fini ( Int exitcode )
4659{
sewardj2d9e8742009-08-07 15:46:56 +00004660 if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)) {
4661 VG_(message)(Vg_UserMsg,
4662 "For counts of detected and suppressed errors, "
4663 "rerun with: -v\n");
4664 }
4665
4666 if (VG_(clo_verbosity) == 1 && !VG_(clo_xml)
4667 && HG_(clo_history_level) >= 2) {
4668 VG_(umsg)(
4669 "Use --history-level=approx or =none to gain increased speed, at\n" );
4670 VG_(umsg)(
4671 "the cost of reduced accuracy of conflicting-access information\n");
4672 }
4673
sewardjb4112022007-11-09 22:49:28 +00004674 if (SHOW_DATA_STRUCTURES)
4675 pp_everything( PP_ALL, "SK_(fini)" );
sewardjf98e1c02008-10-25 16:22:41 +00004676 if (HG_(clo_sanity_flags))
sewardjb4112022007-11-09 22:49:28 +00004677 all__sanity_check("SK_(fini)");
4678
sewardj2d9e8742009-08-07 15:46:56 +00004679 if (VG_(clo_stats)) {
sewardjb4112022007-11-09 22:49:28 +00004680
4681 if (1) {
4682 VG_(printf)("\n");
sewardjb4112022007-11-09 22:49:28 +00004683 HG_(ppWSUstats)( univ_lsets, "univ_lsets" );
sewardjc1fb9d22011-02-28 09:03:44 +00004684 if (HG_(clo_track_lockorders)) {
4685 VG_(printf)("\n");
4686 HG_(ppWSUstats)( univ_laog, "univ_laog" );
4687 }
sewardjb4112022007-11-09 22:49:28 +00004688 }
4689
sewardjf98e1c02008-10-25 16:22:41 +00004690 //zz VG_(printf)("\n");
4691 //zz VG_(printf)(" hbefore: %'10lu queries\n", stats__hbefore_queries);
4692 //zz VG_(printf)(" hbefore: %'10lu cache 0 hits\n", stats__hbefore_cache0s);
4693 //zz VG_(printf)(" hbefore: %'10lu cache > 0 hits\n", stats__hbefore_cacheNs);
4694 //zz VG_(printf)(" hbefore: %'10lu graph searches\n", stats__hbefore_gsearches);
4695 //zz VG_(printf)(" hbefore: %'10lu of which slow\n",
4696 //zz stats__hbefore_gsearches - stats__hbefore_gsearchFs);
4697 //zz VG_(printf)(" hbefore: %'10lu stack high water mark\n",
4698 //zz stats__hbefore_stk_hwm);
4699 //zz VG_(printf)(" hbefore: %'10lu cache invals\n", stats__hbefore_invals);
4700 //zz VG_(printf)(" hbefore: %'10lu probes\n", stats__hbefore_probes);
sewardjb4112022007-11-09 22:49:28 +00004701
4702 VG_(printf)("\n");
barta0b6b2c2008-07-07 06:49:24 +00004703 VG_(printf)(" locksets: %'8d unique lock sets\n",
sewardjb4112022007-11-09 22:49:28 +00004704 (Int)HG_(cardinalityWSU)( univ_lsets ));
sewardjc1fb9d22011-02-28 09:03:44 +00004705 if (HG_(clo_track_lockorders)) {
4706 VG_(printf)(" univ_laog: %'8d unique lock sets\n",
4707 (Int)HG_(cardinalityWSU)( univ_laog ));
4708 }
sewardjb4112022007-11-09 22:49:28 +00004709
sewardjd52392d2008-11-08 20:36:26 +00004710 //VG_(printf)("L(ast)L(ock) map: %'8lu inserts (%d map size)\n",
4711 // stats__ga_LL_adds,
4712 // (Int)(ga_to_lastlock ? VG_(sizeFM)( ga_to_lastlock ) : 0) );
sewardjb4112022007-11-09 22:49:28 +00004713
sewardjf98e1c02008-10-25 16:22:41 +00004714 VG_(printf)(" LockN-to-P map: %'8llu queries (%llu map size)\n",
4715 HG_(stats__LockN_to_P_queries),
4716 HG_(stats__LockN_to_P_get_map_size)() );
sewardjb4112022007-11-09 22:49:28 +00004717
sewardjf98e1c02008-10-25 16:22:41 +00004718 VG_(printf)("string table map: %'8llu queries (%llu map size)\n",
4719 HG_(stats__string_table_queries),
4720 HG_(stats__string_table_get_map_size)() );
sewardjc1fb9d22011-02-28 09:03:44 +00004721 if (HG_(clo_track_lockorders)) {
4722 VG_(printf)(" LAOG: %'8d map size\n",
4723 (Int)(laog ? VG_(sizeFM)( laog ) : 0));
4724 VG_(printf)(" LAOG exposition: %'8d map size\n",
4725 (Int)(laog_exposition ? VG_(sizeFM)( laog_exposition ) : 0));
4726 }
4727
barta0b6b2c2008-07-07 06:49:24 +00004728 VG_(printf)(" locks: %'8lu acquires, "
4729 "%'lu releases\n",
sewardjb4112022007-11-09 22:49:28 +00004730 stats__lockN_acquires,
4731 stats__lockN_releases
4732 );
barta0b6b2c2008-07-07 06:49:24 +00004733 VG_(printf)(" sanity checks: %'8lu\n", stats__sanity_checks);
sewardjb4112022007-11-09 22:49:28 +00004734
4735 VG_(printf)("\n");
sewardjf98e1c02008-10-25 16:22:41 +00004736 libhb_shutdown(True);
sewardjb4112022007-11-09 22:49:28 +00004737 }
4738}
4739
sewardjf98e1c02008-10-25 16:22:41 +00004740/* FIXME: move these somewhere sane */
4741
4742static
4743void for_libhb__get_stacktrace ( Thr* hbt, Addr* frames, UWord nRequest )
4744{
4745 Thread* thr;
4746 ThreadId tid;
4747 UWord nActual;
4748 tl_assert(hbt);
sewardj60626642011-03-10 15:14:37 +00004749 thr = libhb_get_Thr_hgthread( hbt );
sewardjf98e1c02008-10-25 16:22:41 +00004750 tl_assert(thr);
4751 tid = map_threads_maybe_reverse_lookup_SLOW(thr);
4752 nActual = (UWord)VG_(get_StackTrace)( tid, frames, (UInt)nRequest,
4753 NULL, NULL, 0 );
4754 tl_assert(nActual <= nRequest);
4755 for (; nActual < nRequest; nActual++)
4756 frames[nActual] = 0;
4757}
4758
4759static
sewardj23f12002009-07-24 08:45:08 +00004760ExeContext* for_libhb__get_EC ( Thr* hbt )
sewardjf98e1c02008-10-25 16:22:41 +00004761{
4762 Thread* thr;
4763 ThreadId tid;
4764 ExeContext* ec;
4765 tl_assert(hbt);
sewardj60626642011-03-10 15:14:37 +00004766 thr = libhb_get_Thr_hgthread( hbt );
sewardjf98e1c02008-10-25 16:22:41 +00004767 tl_assert(thr);
4768 tid = map_threads_maybe_reverse_lookup_SLOW(thr);
sewardj23f12002009-07-24 08:45:08 +00004769 /* this will assert if tid is invalid */
sewardjf98e1c02008-10-25 16:22:41 +00004770 ec = VG_(record_ExeContext)( tid, 0 );
sewardjd52392d2008-11-08 20:36:26 +00004771 return ec;
sewardjf98e1c02008-10-25 16:22:41 +00004772}
4773
4774
sewardjc1fb9d22011-02-28 09:03:44 +00004775static void hg_post_clo_init ( void )
sewardjb4112022007-11-09 22:49:28 +00004776{
sewardjf98e1c02008-10-25 16:22:41 +00004777 Thr* hbthr_root;
njnf76d27a2009-05-28 01:53:07 +00004778
sewardjc1fb9d22011-02-28 09:03:44 +00004779 /////////////////////////////////////////////
4780 hbthr_root = libhb_init( for_libhb__get_stacktrace,
4781 for_libhb__get_EC );
4782 /////////////////////////////////////////////
4783
4784
4785 if (HG_(clo_track_lockorders))
4786 laog__init();
4787
4788 initialise_data_structures(hbthr_root);
4789}
4790
4791static void hg_pre_clo_init ( void )
4792{
sewardjb4112022007-11-09 22:49:28 +00004793 VG_(details_name) ("Helgrind");
4794 VG_(details_version) (NULL);
4795 VG_(details_description) ("a thread error detector");
4796 VG_(details_copyright_author)(
sewardj9eecbbb2010-05-03 21:37:12 +00004797 "Copyright (C) 2007-2010, and GNU GPL'd, by OpenWorks LLP et al.");
sewardjb4112022007-11-09 22:49:28 +00004798 VG_(details_bug_reports_to) (VG_BUGS_TO);
sewardj9c08c0f2011-03-10 15:01:14 +00004799 VG_(details_avg_translation_sizeB) ( 320 );
sewardjb4112022007-11-09 22:49:28 +00004800
4801 VG_(basic_tool_funcs) (hg_post_clo_init,
4802 hg_instrument,
4803 hg_fini);
4804
4805 VG_(needs_core_errors) ();
sewardjf98e1c02008-10-25 16:22:41 +00004806 VG_(needs_tool_errors) (HG_(eq_Error),
sewardj24118492009-07-15 14:50:02 +00004807 HG_(before_pp_Error),
sewardjf98e1c02008-10-25 16:22:41 +00004808 HG_(pp_Error),
sewardjb4112022007-11-09 22:49:28 +00004809 False,/*show TIDs for errors*/
sewardjf98e1c02008-10-25 16:22:41 +00004810 HG_(update_extra),
4811 HG_(recognised_suppression),
4812 HG_(read_extra_suppression_info),
4813 HG_(error_matches_suppression),
4814 HG_(get_error_name),
sewardj588adef2009-08-15 22:41:51 +00004815 HG_(get_extra_suppression_info));
sewardjb4112022007-11-09 22:49:28 +00004816
sewardj24118492009-07-15 14:50:02 +00004817 VG_(needs_xml_output) ();
4818
sewardjb4112022007-11-09 22:49:28 +00004819 VG_(needs_command_line_options)(hg_process_cmd_line_option,
4820 hg_print_usage,
4821 hg_print_debug_usage);
4822 VG_(needs_client_requests) (hg_handle_client_request);
4823
4824 // FIXME?
4825 //VG_(needs_sanity_checks) (hg_cheap_sanity_check,
4826 // hg_expensive_sanity_check);
4827
4828 VG_(needs_malloc_replacement) (hg_cli__malloc,
4829 hg_cli____builtin_new,
4830 hg_cli____builtin_vec_new,
4831 hg_cli__memalign,
4832 hg_cli__calloc,
4833 hg_cli__free,
4834 hg_cli____builtin_delete,
4835 hg_cli____builtin_vec_delete,
4836 hg_cli__realloc,
njn8b140de2009-02-17 04:31:18 +00004837 hg_cli_malloc_usable_size,
sewardjb4112022007-11-09 22:49:28 +00004838 HG_CLI__MALLOC_REDZONE_SZB );
4839
sewardj849b0ed2008-12-21 10:43:10 +00004840 /* 21 Dec 08: disabled this; it mostly causes H to start more
4841 slowly and use significantly more memory, without very often
4842 providing useful results. The user can request to load this
4843 information manually with --read-var-info=yes. */
4844 if (0) VG_(needs_var_info)(); /* optional */
sewardjb4112022007-11-09 22:49:28 +00004845
4846 VG_(track_new_mem_startup) ( evh__new_mem_w_perms );
sewardj7cf4e6b2008-05-01 20:24:26 +00004847 VG_(track_new_mem_stack_signal)( evh__new_mem_w_tid );
4848 VG_(track_new_mem_brk) ( evh__new_mem_w_tid );
sewardjb4112022007-11-09 22:49:28 +00004849 VG_(track_new_mem_mmap) ( evh__new_mem_w_perms );
sewardj1f77fec2010-04-12 19:51:04 +00004850 VG_(track_new_mem_stack) ( evh__new_mem_stack );
sewardjb4112022007-11-09 22:49:28 +00004851
4852 // FIXME: surely this isn't thread-aware
sewardj23f12002009-07-24 08:45:08 +00004853 VG_(track_copy_mem_remap) ( evh__copy_mem );
sewardjb4112022007-11-09 22:49:28 +00004854
4855 VG_(track_change_mem_mprotect) ( evh__set_perms );
4856
4857 VG_(track_die_mem_stack_signal)( evh__die_mem );
sewardjfd35d492011-03-17 19:39:55 +00004858 VG_(track_die_mem_brk) ( evh__die_mem_munmap );
4859 VG_(track_die_mem_munmap) ( evh__die_mem_munmap );
sewardjb4112022007-11-09 22:49:28 +00004860 VG_(track_die_mem_stack) ( evh__die_mem );
4861
4862 // FIXME: what is this for?
4863 VG_(track_ban_mem_stack) (NULL);
4864
4865 VG_(track_pre_mem_read) ( evh__pre_mem_read );
4866 VG_(track_pre_mem_read_asciiz) ( evh__pre_mem_read_asciiz );
4867 VG_(track_pre_mem_write) ( evh__pre_mem_write );
4868 VG_(track_post_mem_write) (NULL);
4869
4870 /////////////////
4871
4872 VG_(track_pre_thread_ll_create)( evh__pre_thread_ll_create );
4873 VG_(track_pre_thread_ll_exit) ( evh__pre_thread_ll_exit );
4874
4875 VG_(track_start_client_code)( evh__start_client_code );
4876 VG_(track_stop_client_code)( evh__stop_client_code );
4877
sewardjb4112022007-11-09 22:49:28 +00004878 /* Ensure that requirements for "dodgy C-as-C++ style inheritance"
4879 as described in comments at the top of pub_tool_hashtable.h, are
4880 met. Blargh. */
4881 tl_assert( sizeof(void*) == sizeof(struct _MallocMeta*) );
4882 tl_assert( sizeof(UWord) == sizeof(Addr) );
4883 hg_mallocmeta_table
4884 = VG_(HT_construct)( "hg_malloc_metadata_table" );
4885
sewardj61bc2c52011-02-09 10:34:00 +00004886 // add a callback to clean up on (threaded) fork.
4887 VG_(atfork)(NULL/*pre*/, NULL/*parent*/, evh__atfork_child/*child*/);
sewardjb4112022007-11-09 22:49:28 +00004888}
4889
4890VG_DETERMINE_INTERFACE_VERSION(hg_pre_clo_init)
4891
4892/*--------------------------------------------------------------------*/
4893/*--- end hg_main.c ---*/
4894/*--------------------------------------------------------------------*/