blob: a0c6a1a84e8a7dccab8a48ae8adfe0ea8dac4e02 [file] [log] [blame]
sewardjaf44c822007-11-25 14:01:38 +00001
2/*--------------------------------------------------------------------*/
3/*--- Client-space code for drd. drd_preloaded.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7 This file is part of drd, a data race detector.
8
9 Copyright (C) 2006-2007 Bart Van Assche
10 bart.vanassche@gmail.com
11
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation; either version 2 of the
15 License, or (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful, but
18 WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25 02111-1307, USA.
26
27 The GNU General Public License is contained in the file COPYING.
28*/
29
30/* ---------------------------------------------------------------------
31 ALL THE CODE IN THIS FILE RUNS ON THE SIMULATED CPU.
32
33 These functions are not called directly - they're the targets of code
34 redirection or load notifications (see pub_core_redir.h for info).
35 They're named weirdly so that the intercept code can find them when the
36 shared object is initially loaded.
37
38 Note that this filename has the "drd_" prefix because it can appear
39 in stack traces, and the "drd_" makes it a little clearer that it
40 originates from Valgrind.
41 ------------------------------------------------------------------ */
42
43// Make sure pthread_spinlock_t is available on glibc 2.3.2 systems.
44#ifndef _GNU_SOURCE
45#define _GNU_SOURCE
46#endif
47
48#include <assert.h>
49#include <inttypes.h> // uintptr_t
50#include <stdio.h>
51#include <unistd.h>
52#include <pthread.h>
53#include "drd_clientreq.h"
54#include "pub_core_basics.h"
55#include "pub_core_clreq.h"
56#include "pub_core_debuginfo.h" // Needed for pub_core_redir.h
57#include "pub_core_redir.h" // For VG_NOTIFY_ON_LOAD
58#include "pub_tool_threadstate.h"// VG_N_THREADS
sewardjaf44c822007-11-25 14:01:38 +000059
60
61// Defines.
62
63#define PTH_FUNC(ret_ty, f, args...) \
64 ret_ty VG_WRAP_FUNCTION_ZZ(libpthreadZdsoZd0,f)(args); \
65 ret_ty VG_WRAP_FUNCTION_ZZ(libpthreadZdsoZd0,f)(args)
66
67
68// Local data structures.
69
70typedef struct
71{
72 void* (*start)(void*);
73 void* arg;
74 int detachstate;
75#if 0
76 pthread_mutex_t mutex;
77 pthread_cond_t cond;
78#else
79 int wrapper_started;
80#endif
81} VgPosixThreadArgs;
82
83
84// Local variables.
85
86static int vg_main_thread_state_is_set = 0;
87
88
89// Function definitions.
90
91static void vg_start_suppression(const void* const p, size_t const size)
92{
93 int res;
94 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_START_SUPPRESSION,
95 p, size, 0, 0, 0);
96}
97
98#if 0
99static void vg_finish_suppression(const void* const p, size_t const size)
100{
101 int res;
102 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_FINISH_SUPPRESSION,
103 p, size, 0, 0, 0);
104}
105#endif
106
107static void vg_start_recording(void)
108{
109 int res;
110 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_START_RECORDING,
111 pthread_self(), 0, 0, 0, 0);
112}
113
114static void vg_stop_recording(void)
115{
116 int res;
117 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_STOP_RECORDING,
118 pthread_self(), 0, 0, 0, 0);
119}
120
121static void vg_set_joinable(const pthread_t tid, const int joinable)
122{
123 int res;
124 assert(joinable == 0 || joinable == 1);
125#if 0
126 printf("vg_set_joinable(%ld, %d)\n", tid, joinable);
127#endif
128 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__SET_JOINABLE,
129 tid, joinable, 0, 0, 0);
130}
131
132static void* vg_thread_wrapper(void* arg)
133{
134 int res;
135 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__DRD_SUPPRESS_CURRENT_STACK,
136 0, 0, 0, 0, 0);
137
138 {
139 VgPosixThreadArgs* const arg_ptr = (VgPosixThreadArgs*)arg;
140 VgPosixThreadArgs const arg_copy = *arg_ptr;
141 void* result;
142
143#if 0
144 pthread_mutex_lock(arg_ptr->mutex);
145 pthread_cond_signal(arg_ptr->cond);
146 pthread_mutex_unlock(arg_ptr->mutex);
147#else
148 arg_ptr->wrapper_started = 1;
149#endif
150
151 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SET_PTHREADID,
152 pthread_self(), 0, 0, 0, 0);
153 vg_set_joinable(pthread_self(),
154 arg_copy.detachstate == PTHREAD_CREATE_JOINABLE);
155 result = (arg_copy.start)(arg_copy.arg);
156 return result;
157 }
158}
159
160static void vg_set_main_thread_state(void)
161{
162 int res;
163
164 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__DRD_SUPPRESS_CURRENT_STACK,
165 0, 0, 0, 0, 0);
166
sewardjaf44c822007-11-25 14:01:38 +0000167 // Make sure that DRD knows about the main thread's POSIX thread ID.
168 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SET_PTHREADID,
169 pthread_self(), 0, 0, 0, 0);
170
171}
172
173// pthread_create
174PTH_FUNC(int, pthreadZucreateZAZa, // pthread_create@*
175 pthread_t *thread, const pthread_attr_t *attr,
176 void *(*start) (void *), void *arg)
177{
178 int ret;
179 OrigFn fn;
180 VgPosixThreadArgs vgargs;
181
182 VALGRIND_GET_ORIG_FN(fn);
183
184 if (vg_main_thread_state_is_set == 0)
185 {
186 vg_set_main_thread_state();
187 vg_main_thread_state_is_set = 1;
188 }
189 vg_start_suppression(&vgargs.wrapper_started,
190 sizeof(vgargs.wrapper_started));
191 vgargs.start = start;
192 vgargs.arg = arg;
193 vgargs.wrapper_started = 0;
194 vgargs.detachstate = PTHREAD_CREATE_JOINABLE;
195 if (attr)
196 {
197 if (pthread_attr_getdetachstate(attr, &vgargs.detachstate) != 0)
198 {
199 assert(0);
200 }
sewardjaf44c822007-11-25 14:01:38 +0000201 }
202 assert(vgargs.detachstate == PTHREAD_CREATE_JOINABLE
203 || vgargs.detachstate == PTHREAD_CREATE_DETACHED);
204#if 0
205 pthread_mutex_init(&vgargs.mutex, 0);
206 pthread_cond_init(&vgargs.cond, 0);
207 pthread_mutex_lock(&vgargs.mutex);
208#endif
209 vg_stop_recording();
210 CALL_FN_W_WWWW(ret, fn, thread, attr, vg_thread_wrapper, &vgargs);
211 vg_start_recording();
212#if 0
213 pthread_cond_wait(&vgargs.cond, &vgargs.mutex);
214 pthread_mutex_unlock(&vgargs.mutex);
215 pthread_cond_destroy(&vgargs.cond);
216 pthread_mutex_destroy(&vgargs.mutex);
217#else
218 // Yes, you see it correctly, busy waiting ... The problem is that
219 // POSIX threads functions cannot be called here -- the functions defined
220 // in this file (vg_preloaded.c) would be called instead of those in
221 // libpthread.so. This loop is necessary because vgargs is allocated on the
222 // stack, and the created thread reads it.
sewardje0744f02007-12-01 02:09:50 +0000223 if (ret == 0)
sewardjaf44c822007-11-25 14:01:38 +0000224 {
sewardje0744f02007-12-01 02:09:50 +0000225 while (! vgargs.wrapper_started)
226 {
227 sched_yield();
228 }
sewardjaf44c822007-11-25 14:01:38 +0000229 }
230#endif
231 return ret;
232}
233
234// pthread_join
235PTH_FUNC(int, pthreadZujoin, // pthread_join
236 pthread_t pt_joinee, void **thread_return)
237{
238 int ret;
239 int res;
240 OrigFn fn;
241
242 VALGRIND_GET_ORIG_FN(fn);
243 CALL_FN_W_WW(ret, fn, pt_joinee, thread_return);
244 if (ret == 0)
245 {
246 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_THREAD_JOIN,
247 pt_joinee, 0, 0, 0, 0);
248 }
249 return ret;
250}
251
252// pthread_detach
253PTH_FUNC(int, pthreadZudetach, pthread_t pt_thread)
254{
255 int ret;
256 OrigFn fn;
257 VALGRIND_GET_ORIG_FN(fn);
258 {
259 CALL_FN_W_W(ret, fn, pt_thread);
260 if (ret == 0)
261 {
262 vg_set_joinable(pt_thread, 0);
263 }
264 }
265 return ret;
266}
267
268// pthread_mutex_init
269PTH_FUNC(int, pthreadZumutexZuinit,
270 pthread_mutex_t *mutex,
271 const pthread_mutexattr_t* attr)
272{
273 int ret;
274 int res;
275 OrigFn fn;
276 VALGRIND_GET_ORIG_FN(fn);
277 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_MUTEX_INIT,
sewardj721ad7b2007-11-30 08:30:29 +0000278 mutex, sizeof(*mutex), mutex_type_mutex, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000279 CALL_FN_W_WW(ret, fn, mutex, attr);
280 return ret;
281}
282
283// pthread_mutex_destroy
284PTH_FUNC(int, pthreadZumutexZudestroy,
285 pthread_mutex_t *mutex)
286{
287 int ret;
288 int res;
289 OrigFn fn;
290 VALGRIND_GET_ORIG_FN(fn);
291 CALL_FN_W_W(ret, fn, mutex);
292 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_DESTROY,
sewardj721ad7b2007-11-30 08:30:29 +0000293 mutex, mutex_type_mutex, 0, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000294 return ret;
295}
296
297// pthread_mutex_lock
298PTH_FUNC(int, pthreadZumutexZulock, // pthread_mutex_lock
299 pthread_mutex_t *mutex)
300{
301 int ret;
302 int res;
303 OrigFn fn;
304 VALGRIND_GET_ORIG_FN(fn);
305 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__PRE_PTHREAD_MUTEX_LOCK,
sewardj721ad7b2007-11-30 08:30:29 +0000306 mutex, sizeof(*mutex), mutex_type_mutex, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000307#if 1
308 // The only purpose of the system call below is to make drd work on AMD64
309 // systems. Without this system call, clients crash (SIGSEGV) in
310 // std::locale::locale().
311 write(1, "", 0);
312#endif
313 CALL_FN_W_W(ret, fn, mutex);
314 if (ret == 0)
315 VALGRIND_DO_CLIENT_REQUEST(res, 0, VG_USERREQ__POST_PTHREAD_MUTEX_LOCK,
sewardj721ad7b2007-11-30 08:30:29 +0000316 mutex, sizeof(*mutex), mutex_type_mutex, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000317 return ret;
318}
319
320// pthread_mutex_trylock
321PTH_FUNC(int, pthreadZumutexZutrylock, // pthread_mutex_trylock
322 pthread_mutex_t *mutex)
323{
324 int ret;
325 int res;
326 OrigFn fn;
327 VALGRIND_GET_ORIG_FN(fn);
328 CALL_FN_W_W(ret, fn, mutex);
329 if (ret == 0)
330 {
331 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_MUTEX_LOCK,
sewardj721ad7b2007-11-30 08:30:29 +0000332 mutex, sizeof(*mutex), mutex_type_mutex, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000333 }
334 return ret;
335}
336
337// pthread_mutex_unlock
338PTH_FUNC(int, pthreadZumutexZuunlock, // pthread_mutex_unlock
339 pthread_mutex_t *mutex)
340{
341 int ret;
342 int res;
343 OrigFn fn;
344 VALGRIND_GET_ORIG_FN(fn);
345 VALGRIND_DO_CLIENT_REQUEST(res, -1,
346 VG_USERREQ__PRE_PTHREAD_MUTEX_UNLOCK,
sewardj721ad7b2007-11-30 08:30:29 +0000347 mutex, sizeof(*mutex), mutex_type_mutex, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000348 CALL_FN_W_W(ret, fn, mutex);
349 return ret;
350}
351
352// pthread_cond_init
353PTH_FUNC(int, pthreadZucondZuinitZAZa, // pthread_cond_init@*
354 pthread_cond_t* cond,
355 const pthread_condattr_t* attr)
356{
357 int ret;
358 int res;
359 OrigFn fn;
360 VALGRIND_GET_ORIG_FN(fn);
361 CALL_FN_W_WW(ret, fn, cond, attr);
362 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_COND_INIT,
363 cond, sizeof(*cond), 0, 0, 0);
364 return ret;
365}
366
367// pthread_cond_destroy
368PTH_FUNC(int, pthreadZucondZudestroyZAZa, // pthread_cond_destroy@*
369 pthread_cond_t* cond)
370{
371 int ret;
372 int res;
373 OrigFn fn;
374 VALGRIND_GET_ORIG_FN(fn);
375 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_PTHREAD_COND_DESTROY,
sewardj721ad7b2007-11-30 08:30:29 +0000376 cond, 0, 0, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000377 CALL_FN_W_W(ret, fn, cond);
378 return ret;
379}
380
381// pthread_cond_wait
382PTH_FUNC(int, pthreadZucondZuwaitZAZa, // pthread_cond_wait@*
383 pthread_cond_t *cond,
384 pthread_mutex_t *mutex)
385{
386 int ret;
387 int res;
388 OrigFn fn;
389 VALGRIND_GET_ORIG_FN(fn);
390 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_PTHREAD_COND_WAIT,
sewardj721ad7b2007-11-30 08:30:29 +0000391 cond, sizeof(*cond), mutex, sizeof(*mutex), 0);
sewardjaf44c822007-11-25 14:01:38 +0000392 CALL_FN_W_WW(ret, fn, cond, mutex);
393 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_COND_WAIT,
sewardj721ad7b2007-11-30 08:30:29 +0000394 cond, sizeof(*cond), mutex, sizeof(*mutex), 0);
sewardjaf44c822007-11-25 14:01:38 +0000395 return ret;
396}
397
398// pthread_cond_timedwait
399PTH_FUNC(int, pthreadZucondZutimedwaitZAZa, // pthread_cond_timedwait@*
400 pthread_cond_t *cond,
401 pthread_mutex_t *mutex,
402 const struct timespec* abstime)
403{
404 int ret;
405 int res;
406 OrigFn fn;
407 VALGRIND_GET_ORIG_FN(fn);
408 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_PTHREAD_COND_WAIT,
sewardj721ad7b2007-11-30 08:30:29 +0000409 cond, sizeof(*cond), mutex, sizeof(*mutex), 0);
sewardjaf44c822007-11-25 14:01:38 +0000410 CALL_FN_W_WWW(ret, fn, cond, mutex, abstime);
411 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_COND_WAIT,
sewardj721ad7b2007-11-30 08:30:29 +0000412 cond, sizeof(*cond), mutex, sizeof(*mutex), 0);
sewardjaf44c822007-11-25 14:01:38 +0000413 return ret;
414}
415
416// pthread_cond_signal
417PTH_FUNC(int, pthreadZucondZusignalZAZa, // pthread_cond_signal@*
418 pthread_cond_t* cond)
419{
420 int ret;
421 int res;
422 OrigFn fn;
423 VALGRIND_GET_ORIG_FN(fn);
424 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_PTHREAD_COND_SIGNAL,
425 cond, 0, 0, 0, 0);
426 CALL_FN_W_W(ret, fn, cond);
427 return ret;
428}
429
430// pthread_cond_broadcast
431PTH_FUNC(int, pthreadZucondZubroadcastZAZa, // pthread_cond_broadcast@*
432 pthread_cond_t* cond)
433{
434 int ret;
435 int res;
436 OrigFn fn;
437 VALGRIND_GET_ORIG_FN(fn);
438 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__PRE_PTHREAD_COND_BROADCAST,
439 cond, 0, 0, 0, 0);
440 CALL_FN_W_W(ret, fn, cond);
441 return ret;
442}
443
444
445// pthread_spin_init
446PTH_FUNC(int, pthreadZuspinZuinit, // pthread_spin_init
447 pthread_spinlock_t *spinlock,
448 int pshared)
449{
450 int ret;
451 int res;
452 OrigFn fn;
453 VALGRIND_GET_ORIG_FN(fn);
454 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SPIN_INIT_OR_UNLOCK,
sewardj721ad7b2007-11-30 08:30:29 +0000455 spinlock, sizeof(*spinlock),
456 mutex_type_spinlock, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000457 CALL_FN_W_WW(ret, fn, spinlock, pshared);
458 return ret;
459}
460
461// pthread_spin_destroy
462PTH_FUNC(int, pthreadZuspinZudestroy, // pthread_spin_destroy
463 pthread_spinlock_t *spinlock)
464{
465 int ret;
466 int res;
467 OrigFn fn;
468 VALGRIND_GET_ORIG_FN(fn);
469 CALL_FN_W_W(ret, fn, spinlock);
470 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_MUTEX_DESTROY,
sewardj721ad7b2007-11-30 08:30:29 +0000471 spinlock, mutex_type_spinlock, 0, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000472 return ret;
473}
474
475// pthread_spin_lock
476PTH_FUNC(int, pthreadZuspinZulock, // pthread_spin_lock
477 pthread_spinlock_t *spinlock)
478{
479 int ret;
480 int res;
481 OrigFn fn;
482 VALGRIND_GET_ORIG_FN(fn);
483 CALL_FN_W_W(ret, fn, spinlock);
484 if (ret == 0)
485 {
486 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_MUTEX_LOCK,
sewardj721ad7b2007-11-30 08:30:29 +0000487 spinlock, sizeof(*spinlock),
488 mutex_type_spinlock, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000489 }
490 return ret;
491}
492
493// pthread_spin_trylock
494PTH_FUNC(int, pthreadZuspinZutrylock, // pthread_spin_trylock
495 pthread_spinlock_t *spinlock)
496{
497 int ret;
498 int res;
499 OrigFn fn;
500 VALGRIND_GET_ORIG_FN(fn);
501 CALL_FN_W_W(ret, fn, spinlock);
502 if (ret == 0)
503 {
504 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__POST_PTHREAD_MUTEX_LOCK,
sewardj721ad7b2007-11-30 08:30:29 +0000505 spinlock, sizeof(*spinlock),
506 mutex_type_spinlock, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000507 }
508 return ret;
509}
510
511// pthread_spin_unlock
512PTH_FUNC(int, pthreadZuspinZuunlock, // pthread_spin_unlock
513 pthread_spinlock_t *spinlock)
514{
515 int ret;
516 int res;
517 OrigFn fn;
518 VALGRIND_GET_ORIG_FN(fn);
519 VALGRIND_DO_CLIENT_REQUEST(res, -1, VG_USERREQ__SPIN_INIT_OR_UNLOCK,
sewardj721ad7b2007-11-30 08:30:29 +0000520 spinlock, sizeof(*spinlock),
521 mutex_type_spinlock, 0, 0);
sewardjaf44c822007-11-25 14:01:38 +0000522 CALL_FN_W_W(ret, fn, spinlock);
523 return ret;
524}
525
526/*
527 * Local variables:
528 * c-basic-offset: 3
529 * End:
530 */