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