1 /* -*- mode: C; c-basic-offset: 3; indent-tabs-mode: nil; -*- */
2 /*
3 This file is part of drd, a thread error detector.
4
5 Copyright (C) 2006-2011 Bart Van Assche <bvanassche@acm.org>.
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20 02111-1307, USA.
21
22 The GNU General Public License is contained in the file COPYING.
23 */
24
25
26 #include "drd_barrier.h"
27 #include "drd_clientreq.h"
28 #include "drd_cond.h"
29 #include "drd_error.h"
30 #include "drd_hb.h"
31 #include "drd_load_store.h"
32 #include "drd_malloc_wrappers.h"
33 #include "drd_mutex.h"
34 #include "drd_rwlock.h"
35 #include "drd_semaphore.h"
36 #include "drd_suppression.h" // drd_start_suppression()
37 #include "drd_thread.h"
38 #include "pub_tool_basics.h" // Bool
39 #include "pub_tool_debuginfo.h" // VG_(describe_IP)()
40 #include "pub_tool_libcassert.h"
41 #include "pub_tool_libcassert.h" // tl_assert()
42 #include "pub_tool_libcprint.h" // VG_(message)()
43 #include "pub_tool_machine.h" // VG_(get_SP)()
44 #include "pub_tool_threadstate.h"
45 #include "pub_tool_tooliface.h" // VG_(needs_...)()
46
47
48 /* Global variables. */
49
50 Bool DRD_(g_free_is_write);
51
52
53 /* Local function declarations. */
54
55 static Bool handle_client_request(ThreadId vg_tid, UWord* arg, UWord* ret);
56
57
58 /* Function definitions. */
59
60 /**
61 * Tell the Valgrind core the address of the DRD function that processes
62 * client requests. Must be called before any client code is run.
63 */
DRD_(clientreq_init)64 void DRD_(clientreq_init)(void)
65 {
66 VG_(needs_client_requests)(handle_client_request);
67 }
68
69 /**
70 * DRD's handler for Valgrind client requests. The code below handles both
71 * DRD's public and tool-internal client requests.
72 */
handle_client_request(ThreadId vg_tid,UWord * arg,UWord * ret)73 static Bool handle_client_request(ThreadId vg_tid, UWord* arg, UWord* ret)
74 {
75 UWord result = 0;
76 const DrdThreadId drd_tid = DRD_(thread_get_running_tid)();
77
78 tl_assert(vg_tid == VG_(get_running_tid()));
79 tl_assert(DRD_(VgThreadIdToDrdThreadId)(vg_tid) == drd_tid);
80
81 switch (arg[0])
82 {
83 case VG_USERREQ__MALLOCLIKE_BLOCK:
84 if (DRD_(g_free_is_write)) {
85 GenericErrInfo GEI = {
86 .tid = DRD_(thread_get_running_tid)(),
87 .addr = 0,
88 };
89 VG_(maybe_record_error)(vg_tid,
90 GenericErr,
91 VG_(get_IP)(vg_tid),
92 "--free-is-write=yes is incompatible with"
93 " custom memory allocator client requests",
94 &GEI);
95 }
96 if (arg[1])
97 DRD_(malloclike_block)(vg_tid, arg[1]/*addr*/, arg[2]/*size*/);
98 break;
99
100 case VG_USERREQ__RESIZEINPLACE_BLOCK:
101 if (!DRD_(freelike_block)(vg_tid, arg[1]/*addr*/, False))
102 {
103 GenericErrInfo GEI = {
104 .tid = DRD_(thread_get_running_tid)(),
105 .addr = 0,
106 };
107 VG_(maybe_record_error)(vg_tid,
108 GenericErr,
109 VG_(get_IP)(vg_tid),
110 "Invalid VG_USERREQ__RESIZEINPLACE_BLOCK request",
111 &GEI);
112 }
113 DRD_(malloclike_block)(vg_tid, arg[1]/*addr*/, arg[3]/*newSize*/);
114 break;
115
116 case VG_USERREQ__FREELIKE_BLOCK:
117 if (arg[1] && ! DRD_(freelike_block)(vg_tid, arg[1]/*addr*/, False))
118 {
119 GenericErrInfo GEI = {
120 .tid = DRD_(thread_get_running_tid)(),
121 .addr = 0,
122 };
123 VG_(maybe_record_error)(vg_tid,
124 GenericErr,
125 VG_(get_IP)(vg_tid),
126 "Invalid VG_USERREQ__FREELIKE_BLOCK request",
127 &GEI);
128 }
129 break;
130
131 case VG_USERREQ__DRD_GET_VALGRIND_THREAD_ID:
132 result = vg_tid;
133 break;
134
135 case VG_USERREQ__DRD_GET_DRD_THREAD_ID:
136 result = drd_tid;
137 break;
138
139 case VG_USERREQ__DRD_SET_THREAD_NAME:
140 DRD_(thread_set_name)(drd_tid, (const char*)arg[1]);
141 break;
142
143 case VG_USERREQ__DRD_START_SUPPRESSION:
144 /*_VG_USERREQ__HG_ARANGE_MAKE_UNTRACKED*/
145 case VG_USERREQ_TOOL_BASE('H','G') + 256 + 39:
146 DRD_(start_suppression)(arg[1], arg[1] + arg[2], "client");
147 break;
148
149 case VG_USERREQ__DRD_FINISH_SUPPRESSION:
150 /*_VG_USERREQ__HG_ARANGE_MAKE_TRACKED*/
151 case VG_USERREQ_TOOL_BASE('H','G') + 256 + 40:
152 DRD_(finish_suppression)(arg[1], arg[1] + arg[2]);
153 break;
154
155 case VG_USERREQ__DRD_ANNOTATE_HAPPENS_BEFORE:
156 DRD_(hb_happens_before)(drd_tid, arg[1]);
157 break;
158
159 case VG_USERREQ__DRD_ANNOTATE_HAPPENS_AFTER:
160 DRD_(hb_happens_after)(drd_tid, arg[1]);
161 break;
162
163 case VG_USERREQ__DRD_ANNOTATE_RWLOCK_CREATE:
164 if (arg[1])
165 {
166 struct mutex_info* const mutex_p = DRD_(mutex_get)(arg[1]);
167 if (mutex_p && mutex_p->mutex_type == mutex_type_spinlock)
168 break;
169 }
170 DRD_(rwlock_pre_init)(arg[1], user_rwlock);
171 break;
172
173 case VG_USERREQ__DRD_ANNOTATE_RWLOCK_DESTROY:
174 if (arg[1])
175 {
176 struct mutex_info* const mutex_p = DRD_(mutex_get)(arg[1]);
177 if (mutex_p && mutex_p->mutex_type == mutex_type_spinlock)
178 break;
179 }
180 DRD_(rwlock_post_destroy)(arg[1], user_rwlock);
181 break;
182
183 case VG_USERREQ__DRD_ANNOTATE_RWLOCK_ACQUIRED:
184 if (arg[1])
185 {
186 struct mutex_info* const mutex_p = DRD_(mutex_get)(arg[1]);
187 if (mutex_p && mutex_p->mutex_type == mutex_type_spinlock)
188 break;
189 }
190 tl_assert(arg[2] == !! arg[2]);
191 if (arg[2])
192 {
193 DRD_(rwlock_pre_wrlock)(arg[1], user_rwlock);
194 DRD_(rwlock_post_wrlock)(arg[1], user_rwlock, True);
195 }
196 else
197 {
198 DRD_(rwlock_pre_rdlock)(arg[1], user_rwlock);
199 DRD_(rwlock_post_rdlock)(arg[1], user_rwlock, True);
200 }
201 break;
202
203 case VG_USERREQ__DRD_ANNOTATE_RWLOCK_RELEASED:
204 if (arg[1])
205 {
206 struct mutex_info* const mutex_p = DRD_(mutex_get)(arg[1]);
207 if (mutex_p && mutex_p->mutex_type == mutex_type_spinlock)
208 break;
209 }
210 tl_assert(arg[2] == !! arg[2]);
211 DRD_(rwlock_pre_unlock)(arg[1], user_rwlock);
212 break;
213
214 case VG_USERREQ__SET_PTHREAD_COND_INITIALIZER:
215 DRD_(pthread_cond_initializer) = (Addr)arg[1];
216 DRD_(pthread_cond_initializer_size) = arg[2];
217 break;
218
219 case VG_USERREQ__DRD_START_NEW_SEGMENT:
220 DRD_(thread_new_segment)(DRD_(PtThreadIdToDrdThreadId)(arg[1]));
221 break;
222
223 case VG_USERREQ__DRD_START_TRACE_ADDR:
224 DRD_(start_tracing_address_range)(arg[1], arg[1] + arg[2]);
225 break;
226
227 case VG_USERREQ__DRD_STOP_TRACE_ADDR:
228 DRD_(stop_tracing_address_range)(arg[1], arg[1] + arg[2]);
229 break;
230
231 case VG_USERREQ__DRD_RECORD_LOADS:
232 DRD_(thread_set_record_loads)(drd_tid, arg[1]);
233 break;
234
235 case VG_USERREQ__DRD_RECORD_STORES:
236 DRD_(thread_set_record_stores)(drd_tid, arg[1]);
237 break;
238
239 case VG_USERREQ__SET_PTHREADID:
240 // pthread_self() returns 0 for programs not linked with libpthread.so.
241 if (arg[1] != INVALID_POSIX_THREADID)
242 DRD_(thread_set_pthreadid)(drd_tid, arg[1]);
243 break;
244
245 case VG_USERREQ__SET_JOINABLE:
246 {
247 const DrdThreadId drd_joinable = DRD_(PtThreadIdToDrdThreadId)(arg[1]);
248 if (drd_joinable != DRD_INVALID_THREADID)
249 DRD_(thread_set_joinable)(drd_joinable, (Bool)arg[2]);
250 else {
251 InvalidThreadIdInfo ITI = { DRD_(thread_get_running_tid)(), arg[1] };
252 VG_(maybe_record_error)(vg_tid,
253 InvalidThreadId,
254 VG_(get_IP)(vg_tid),
255 "pthread_detach(): invalid thread ID",
256 &ITI);
257 }
258 break;
259 }
260
261 case VG_USERREQ__ENTERING_PTHREAD_CREATE:
262 DRD_(thread_entering_pthread_create)(drd_tid);
263 break;
264
265 case VG_USERREQ__LEFT_PTHREAD_CREATE:
266 DRD_(thread_left_pthread_create)(drd_tid);
267 break;
268
269 case VG_USERREQ__POST_THREAD_JOIN:
270 {
271 const DrdThreadId thread_to_join = DRD_(PtThreadIdToDrdThreadId)(arg[1]);
272 if (thread_to_join == DRD_INVALID_THREADID)
273 {
274 InvalidThreadIdInfo ITI = { DRD_(thread_get_running_tid)(), arg[1] };
275 VG_(maybe_record_error)(vg_tid,
276 InvalidThreadId,
277 VG_(get_IP)(vg_tid),
278 "pthread_join(): invalid thread ID",
279 &ITI);
280 }
281 else
282 {
283 DRD_(thread_post_join)(drd_tid, thread_to_join);
284 }
285 break;
286 }
287
288 case VG_USERREQ__PRE_THREAD_CANCEL:
289 {
290 const DrdThreadId thread_to_cancel =DRD_(PtThreadIdToDrdThreadId)(arg[1]);
291 if (thread_to_cancel == DRD_INVALID_THREADID)
292 {
293 InvalidThreadIdInfo ITI = { DRD_(thread_get_running_tid)(), arg[1] };
294 VG_(maybe_record_error)(vg_tid,
295 InvalidThreadId,
296 VG_(get_IP)(vg_tid),
297 "pthread_cancel(): invalid thread ID",
298 &ITI);
299 }
300 else
301 {
302 DRD_(thread_pre_cancel)(thread_to_cancel);
303 }
304 break;
305 }
306
307 case VG_USERREQ__POST_THREAD_CANCEL:
308 break;
309
310 case VG_USERREQ__PRE_MUTEX_INIT:
311 if (DRD_(thread_enter_synchr)(drd_tid) == 0)
312 DRD_(mutex_init)(arg[1], arg[2]);
313 break;
314
315 case VG_USERREQ__POST_MUTEX_INIT:
316 DRD_(thread_leave_synchr)(drd_tid);
317 break;
318
319 case VG_USERREQ__PRE_MUTEX_DESTROY:
320 DRD_(thread_enter_synchr)(drd_tid);
321 break;
322
323 case VG_USERREQ__POST_MUTEX_DESTROY:
324 if (DRD_(thread_leave_synchr)(drd_tid) == 0)
325 DRD_(mutex_post_destroy)(arg[1]);
326 break;
327
328 case VG_USERREQ__PRE_MUTEX_LOCK:
329 if (DRD_(thread_enter_synchr)(drd_tid) == 0)
330 DRD_(mutex_pre_lock)(arg[1], arg[2], arg[3]);
331 break;
332
333 case VG_USERREQ__POST_MUTEX_LOCK:
334 if (DRD_(thread_leave_synchr)(drd_tid) == 0)
335 DRD_(mutex_post_lock)(arg[1], arg[2], False/*post_cond_wait*/);
336 break;
337
338 case VG_USERREQ__PRE_MUTEX_UNLOCK:
339 if (DRD_(thread_enter_synchr)(drd_tid) == 0)
340 DRD_(mutex_unlock)(arg[1], arg[2]);
341 break;
342
343 case VG_USERREQ__POST_MUTEX_UNLOCK:
344 DRD_(thread_leave_synchr)(drd_tid);
345 break;
346
347 case VG_USERREQ__PRE_SPIN_INIT_OR_UNLOCK:
348 if (DRD_(thread_enter_synchr)(drd_tid) == 0)
349 DRD_(spinlock_init_or_unlock)(arg[1]);
350 break;
351
352 case VG_USERREQ__POST_SPIN_INIT_OR_UNLOCK:
353 DRD_(thread_leave_synchr)(drd_tid);
354 break;
355
356 case VG_USERREQ__PRE_COND_INIT:
357 if (DRD_(thread_enter_synchr)(drd_tid) == 0)
358 DRD_(cond_pre_init)(arg[1]);
359 break;
360
361 case VG_USERREQ__POST_COND_INIT:
362 DRD_(thread_leave_synchr)(drd_tid);
363 break;
364
365 case VG_USERREQ__PRE_COND_DESTROY:
366 DRD_(thread_enter_synchr)(drd_tid);
367 break;
368
369 case VG_USERREQ__POST_COND_DESTROY:
370 if (DRD_(thread_leave_synchr)(drd_tid) == 0)
371 DRD_(cond_post_destroy)(arg[1]);
372 break;
373
374 case VG_USERREQ__PRE_COND_WAIT:
375 if (DRD_(thread_enter_synchr)(drd_tid) == 0)
376 {
377 const Addr cond = arg[1];
378 const Addr mutex = arg[2];
379 const MutexT mutex_type = arg[3];
380 DRD_(mutex_unlock)(mutex, mutex_type);
381 DRD_(cond_pre_wait)(cond, mutex);
382 }
383 break;
384
385 case VG_USERREQ__POST_COND_WAIT:
386 if (DRD_(thread_leave_synchr)(drd_tid) == 0)
387 {
388 const Addr cond = arg[1];
389 const Addr mutex = arg[2];
390 const Bool took_lock = arg[3];
391 DRD_(cond_post_wait)(cond);
392 DRD_(mutex_post_lock)(mutex, took_lock, True);
393 }
394 break;
395
396 case VG_USERREQ__PRE_COND_SIGNAL:
397 if (DRD_(thread_enter_synchr)(drd_tid) == 0)
398 DRD_(cond_pre_signal)(arg[1]);
399 break;
400
401 case VG_USERREQ__POST_COND_SIGNAL:
402 DRD_(thread_leave_synchr)(drd_tid);
403 break;
404
405 case VG_USERREQ__PRE_COND_BROADCAST:
406 if (DRD_(thread_enter_synchr)(drd_tid) == 0)
407 DRD_(cond_pre_broadcast)(arg[1]);
408 break;
409
410 case VG_USERREQ__POST_COND_BROADCAST:
411 DRD_(thread_leave_synchr)(drd_tid);
412 break;
413
414 case VG_USERREQ__PRE_SEM_INIT:
415 if (DRD_(thread_enter_synchr)(drd_tid) == 0)
416 DRD_(semaphore_init)(arg[1], arg[2], arg[3]);
417 break;
418
419 case VG_USERREQ__POST_SEM_INIT:
420 DRD_(thread_leave_synchr)(drd_tid);
421 break;
422
423 case VG_USERREQ__PRE_SEM_DESTROY:
424 DRD_(thread_enter_synchr)(drd_tid);
425 break;
426
427 case VG_USERREQ__POST_SEM_DESTROY:
428 if (DRD_(thread_leave_synchr)(drd_tid) == 0)
429 DRD_(semaphore_destroy)(arg[1]);
430 break;
431
432 case VG_USERREQ__PRE_SEM_OPEN:
433 DRD_(thread_enter_synchr)(drd_tid);
434 break;
435
436 case VG_USERREQ__POST_SEM_OPEN:
437 if (DRD_(thread_leave_synchr)(drd_tid) == 0)
438 DRD_(semaphore_open)(arg[1], (Char*)arg[2], arg[3], arg[4], arg[5]);
439 break;
440
441 case VG_USERREQ__PRE_SEM_CLOSE:
442 if (DRD_(thread_enter_synchr)(drd_tid) == 0)
443 DRD_(semaphore_close)(arg[1]);
444 break;
445
446 case VG_USERREQ__POST_SEM_CLOSE:
447 DRD_(thread_leave_synchr)(drd_tid);
448 break;
449
450 case VG_USERREQ__PRE_SEM_WAIT:
451 if (DRD_(thread_enter_synchr)(drd_tid) == 0)
452 DRD_(semaphore_pre_wait)(arg[1]);
453 break;
454
455 case VG_USERREQ__POST_SEM_WAIT:
456 if (DRD_(thread_leave_synchr)(drd_tid) == 0)
457 DRD_(semaphore_post_wait)(drd_tid, arg[1], arg[2]);
458 break;
459
460 case VG_USERREQ__PRE_SEM_POST:
461 if (DRD_(thread_enter_synchr)(drd_tid) == 0)
462 DRD_(semaphore_pre_post)(drd_tid, arg[1]);
463 break;
464
465 case VG_USERREQ__POST_SEM_POST:
466 if (DRD_(thread_leave_synchr)(drd_tid) == 0)
467 DRD_(semaphore_post_post)(drd_tid, arg[1], arg[2]);
468 break;
469
470 case VG_USERREQ__PRE_BARRIER_INIT:
471 if (DRD_(thread_enter_synchr)(drd_tid) == 0)
472 DRD_(barrier_init)(arg[1], arg[2], arg[3], arg[4]);
473 break;
474
475 case VG_USERREQ__POST_BARRIER_INIT:
476 DRD_(thread_leave_synchr)(drd_tid);
477 break;
478
479 case VG_USERREQ__PRE_BARRIER_DESTROY:
480 DRD_(thread_enter_synchr)(drd_tid);
481 break;
482
483 case VG_USERREQ__POST_BARRIER_DESTROY:
484 if (DRD_(thread_leave_synchr)(drd_tid) == 0)
485 DRD_(barrier_destroy)(arg[1], arg[2]);
486 break;
487
488 case VG_USERREQ__PRE_BARRIER_WAIT:
489 if (DRD_(thread_enter_synchr)(drd_tid) == 0)
490 DRD_(barrier_pre_wait)(drd_tid, arg[1], arg[2]);
491 break;
492
493 case VG_USERREQ__POST_BARRIER_WAIT:
494 if (DRD_(thread_leave_synchr)(drd_tid) == 0)
495 DRD_(barrier_post_wait)(drd_tid, arg[1], arg[2], arg[3], arg[4]);
496 break;
497
498 case VG_USERREQ__PRE_RWLOCK_INIT:
499 DRD_(rwlock_pre_init)(arg[1], pthread_rwlock);
500 break;
501
502 case VG_USERREQ__POST_RWLOCK_DESTROY:
503 DRD_(rwlock_post_destroy)(arg[1], pthread_rwlock);
504 break;
505
506 case VG_USERREQ__PRE_RWLOCK_RDLOCK:
507 if (DRD_(thread_enter_synchr)(drd_tid) == 0)
508 DRD_(rwlock_pre_rdlock)(arg[1], pthread_rwlock);
509 break;
510
511 case VG_USERREQ__POST_RWLOCK_RDLOCK:
512 if (DRD_(thread_leave_synchr)(drd_tid) == 0)
513 DRD_(rwlock_post_rdlock)(arg[1], pthread_rwlock, arg[2]);
514 break;
515
516 case VG_USERREQ__PRE_RWLOCK_WRLOCK:
517 if (DRD_(thread_enter_synchr)(drd_tid) == 0)
518 DRD_(rwlock_pre_wrlock)(arg[1], pthread_rwlock);
519 break;
520
521 case VG_USERREQ__POST_RWLOCK_WRLOCK:
522 if (DRD_(thread_leave_synchr)(drd_tid) == 0)
523 DRD_(rwlock_post_wrlock)(arg[1], pthread_rwlock, arg[2]);
524 break;
525
526 case VG_USERREQ__PRE_RWLOCK_UNLOCK:
527 if (DRD_(thread_enter_synchr)(drd_tid) == 0)
528 DRD_(rwlock_pre_unlock)(arg[1], pthread_rwlock);
529 break;
530
531 case VG_USERREQ__POST_RWLOCK_UNLOCK:
532 DRD_(thread_leave_synchr)(drd_tid);
533 break;
534
535 case VG_USERREQ__DRD_CLEAN_MEMORY:
536 if (arg[2] > 0)
537 DRD_(clean_memory)(arg[1], arg[2]);
538 break;
539
540 case VG_USERREQ__HELGRIND_ANNOTATION_UNIMP:
541 {
542 /* Note: it is assumed below that the text arg[1] points to is never
543 * freed, e.g. because it points to static data.
544 */
545 UnimpClReqInfo UICR =
546 { DRD_(thread_get_running_tid)(), (Char*)arg[1] };
547 VG_(maybe_record_error)(vg_tid,
548 UnimpHgClReq,
549 VG_(get_IP)(vg_tid),
550 "",
551 &UICR);
552 }
553 break;
554
555 case VG_USERREQ__DRD_ANNOTATION_UNIMP:
556 {
557 /* Note: it is assumed below that the text arg[1] points to is never
558 * freed, e.g. because it points to static data.
559 */
560 UnimpClReqInfo UICR =
561 { DRD_(thread_get_running_tid)(), (Char*)arg[1] };
562 VG_(maybe_record_error)(vg_tid,
563 UnimpDrdClReq,
564 VG_(get_IP)(vg_tid),
565 "",
566 &UICR);
567 }
568 break;
569
570 default:
571 #if 0
572 VG_(message)(Vg_DebugMsg, "Unrecognized client request 0x%lx 0x%lx",
573 arg[0], arg[1]);
574 tl_assert(0);
575 #endif
576 return False;
577 }
578
579 *ret = result;
580 return True;
581 }
582