2 This file is part of drd, a thread error detector.
4 Copyright (C) 2006-2024 Bart Van Assche <bvanassche@acm.org>.
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.
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.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, see <http://www.gnu.org/licenses/>.
19 The GNU General Public License is contained in the file COPYING.
23 #include "drd_barrier.h"
24 #include "drd_clientreq.h"
26 #include "drd_error.h"
28 #include "drd_load_store.h"
29 #include "drd_malloc_wrappers.h"
30 #include "drd_mutex.h"
31 #include "drd_rwlock.h"
32 #include "drd_semaphore.h"
33 #include "drd_suppression.h" // drd_start_suppression()
34 #include "drd_thread.h"
35 #include "pub_tool_basics.h" // Bool
36 #include "pub_tool_libcassert.h"
37 #include "pub_tool_libcassert.h" // tl_assert()
38 #include "pub_tool_libcprint.h" // VG_(message)()
39 #include "pub_tool_machine.h" // VG_(get_SP)()
40 #include "pub_tool_threadstate.h"
41 #include "pub_tool_tooliface.h" // VG_(needs_...)()
44 /* Global variables. */
46 Bool
DRD_(g_free_is_write
);
49 /* Function definitions. */
51 static Bool
handle_core_client_request(ThreadId vg_tid
, UWord
* arg
, UWord
* ret
)
53 tl_assert(vg_tid
== VG_(get_running_tid
)());
57 case VG_USERREQ__MALLOCLIKE_BLOCK
:
58 if (DRD_(g_free_is_write
)) {
59 GenericErrInfo GEI
= {
60 .tid
= DRD_(thread_get_running_tid
)(),
63 VG_(maybe_record_error
)(vg_tid
,
66 "--free-is-write=yes is incompatible with"
67 " custom memory allocator client requests",
71 DRD_(malloclike_block
)(vg_tid
, arg
[1]/*addr*/, arg
[2]/*size*/);
74 case VG_USERREQ__RESIZEINPLACE_BLOCK
:
75 if (!DRD_(freelike_block
)(vg_tid
, arg
[1]/*addr*/, False
))
77 GenericErrInfo GEI
= {
78 .tid
= DRD_(thread_get_running_tid
)(),
81 VG_(maybe_record_error
)(vg_tid
,
84 "Invalid VG_USERREQ__RESIZEINPLACE_BLOCK request",
87 DRD_(malloclike_block
)(vg_tid
, arg
[1]/*addr*/, arg
[3]/*newSize*/);
90 case VG_USERREQ__FREELIKE_BLOCK
:
91 if (arg
[1] && ! DRD_(freelike_block
)(vg_tid
, arg
[1]/*addr*/, False
))
93 GenericErrInfo GEI
= {
94 .tid
= DRD_(thread_get_running_tid
)(),
97 VG_(maybe_record_error
)(vg_tid
,
100 "Invalid VG_USERREQ__FREELIKE_BLOCK request",
110 #if defined(VGP_mips32_linux) || defined(VGP_mips64_linux)
111 /* There is a cse related issue in gcc for MIPS. Optimization level
112 has to be lowered, so cse related optimizations are not
114 __attribute__((optimize("O1")))
116 static Bool
handle_thr_client_request(ThreadId vg_tid
, UWord
* arg
, UWord
* ret
)
118 const DrdThreadId drd_tid
= DRD_(thread_get_running_tid
)();
121 tl_assert(vg_tid
== VG_(get_running_tid
)());
122 tl_assert(DRD_(VgThreadIdToDrdThreadId
)(vg_tid
) == drd_tid
);
126 case VG_USERREQ__DRD_GET_VALGRIND_THREAD_ID
:
130 case VG_USERREQ__DRD_GET_DRD_THREAD_ID
:
134 case VG_USERREQ__DRD_SET_THREAD_NAME
:
135 DRD_(thread_set_name
)(drd_tid
, (const HChar
*)arg
[1]);
138 case VG_USERREQ__DRD_START_SUPPRESSION
:
139 /*_VG_USERREQ__HG_ARANGE_MAKE_UNTRACKED*/
140 case VG_USERREQ_TOOL_BASE('H','G') + 256 + 39:
141 DRD_(start_suppression
)(arg
[1], arg
[1] + arg
[2], "client");
144 case VG_USERREQ__DRD_FINISH_SUPPRESSION
:
145 /*_VG_USERREQ__HG_ARANGE_MAKE_TRACKED*/
146 case VG_USERREQ_TOOL_BASE('H','G') + 256 + 40:
147 DRD_(finish_suppression
)(arg
[1], arg
[1] + arg
[2]);
150 case VG_USERREQ__DRD_ANNOTATE_HAPPENS_BEFORE
:
151 DRD_(hb_happens_before
)(drd_tid
, arg
[1]);
154 case VG_USERREQ__DRD_ANNOTATE_HAPPENS_AFTER
:
155 DRD_(hb_happens_after
)(drd_tid
, arg
[1]);
158 case VG_USERREQ__DRD_ANNOTATE_RWLOCK_CREATE
:
161 struct mutex_info
* const mutex_p
= DRD_(mutex_get
)(arg
[1]);
162 if (mutex_p
&& mutex_p
->mutex_type
== mutex_type_spinlock
)
165 DRD_(rwlock_pre_init
)(arg
[1], user_rwlock
);
168 case VG_USERREQ__DRD_ANNOTATE_RWLOCK_DESTROY
:
171 struct mutex_info
* const mutex_p
= DRD_(mutex_get
)(arg
[1]);
172 if (mutex_p
&& mutex_p
->mutex_type
== mutex_type_spinlock
)
175 DRD_(rwlock_post_destroy
)(arg
[1], user_rwlock
);
178 case VG_USERREQ__DRD_ANNOTATE_RWLOCK_ACQUIRED
:
181 struct mutex_info
* const mutex_p
= DRD_(mutex_get
)(arg
[1]);
182 if (mutex_p
&& mutex_p
->mutex_type
== mutex_type_spinlock
)
185 tl_assert(arg
[2] == !! arg
[2]);
188 DRD_(rwlock_pre_wrlock
)(arg
[1], user_rwlock
);
189 DRD_(rwlock_post_wrlock
)(arg
[1], user_rwlock
, True
);
193 DRD_(rwlock_pre_rdlock
)(arg
[1], user_rwlock
);
194 DRD_(rwlock_post_rdlock
)(arg
[1], user_rwlock
, True
);
198 case VG_USERREQ__DRD_ANNOTATE_RWLOCK_RELEASED
:
201 struct mutex_info
* const mutex_p
= DRD_(mutex_get
)(arg
[1]);
202 if (mutex_p
&& mutex_p
->mutex_type
== mutex_type_spinlock
)
205 tl_assert(arg
[2] == !! arg
[2]);
206 DRD_(rwlock_pre_unlock
)(arg
[1], user_rwlock
);
209 case VG_USERREQ__DRD_ANNOTATE_SEM_INIT_PRE
:
210 DRD_(semaphore_init
)(arg
[1], 0, arg
[2]);
213 case VG_USERREQ__DRD_ANNOTATE_SEM_DESTROY_POST
:
214 DRD_(semaphore_destroy
)(arg
[1]);
217 case VG_USERREQ__DRD_ANNOTATE_SEM_WAIT_PRE
:
218 DRD_(semaphore_pre_wait
)(arg
[1]);
221 case VG_USERREQ__DRD_ANNOTATE_SEM_WAIT_POST
:
222 DRD_(semaphore_post_wait
)(drd_tid
, arg
[1], True
/* waited */);
225 case VG_USERREQ__DRD_ANNOTATE_SEM_POST_PRE
:
226 DRD_(semaphore_pre_post
)(drd_tid
, arg
[1]);
229 case VG_USERREQ_DRD_SET_PTHREAD_COND_INITIALIZER
:
230 DRD_(pthread_cond_initializer
) = (Addr
)arg
[1];
231 DRD_(pthread_cond_initializer_size
) = arg
[2];
234 case VG_USERREQ_DRD_START_NEW_SEGMENT
:
235 DRD_(thread_new_segment
)(DRD_(PtThreadIdToDrdThreadId
)(arg
[1]));
238 case VG_USERREQ__DRD_START_TRACE_ADDR
:
239 DRD_(start_tracing_address_range
)(arg
[1], arg
[1] + arg
[2], False
);
242 case VG_USERREQ__DRD_STOP_TRACE_ADDR
:
243 DRD_(stop_tracing_address_range
)(arg
[1], arg
[1] + arg
[2]);
246 case VG_USERREQ__DRD_RECORD_LOADS
:
247 DRD_(thread_set_record_loads
)(drd_tid
, arg
[1]);
250 case VG_USERREQ__DRD_RECORD_STORES
:
251 DRD_(thread_set_record_stores
)(drd_tid
, arg
[1]);
254 case VG_USERREQ_DRD_SET_PTHREADID
:
255 // pthread_self() returns 0 for programs not linked with libpthread.so.
256 if (arg
[1] != INVALID_POSIX_THREADID
)
257 DRD_(thread_set_pthreadid
)(drd_tid
, arg
[1]);
260 case VG_USERREQ_DRD_SET_JOINABLE
:
262 const DrdThreadId drd_joinable
= DRD_(PtThreadIdToDrdThreadId
)(arg
[1]);
263 if (drd_joinable
!= DRD_INVALID_THREADID
)
264 DRD_(thread_set_joinable
)(drd_joinable
, (Bool
)arg
[2]);
266 InvalidThreadIdInfo ITI
= { DRD_(thread_get_running_tid
)(), arg
[1] };
267 VG_(maybe_record_error
)(vg_tid
,
270 "pthread_detach(): invalid thread ID",
276 case VG_USERREQ_DRD_ENTERING_PTHREAD_CREATE
:
277 DRD_(thread_entering_pthread_create
)(drd_tid
);
280 case VG_USERREQ_DRD_LEFT_PTHREAD_CREATE
:
281 DRD_(thread_left_pthread_create
)(drd_tid
);
284 case VG_USERREQ_DRD_POST_THREAD_JOIN
:
286 const DrdThreadId thread_to_join
= DRD_(PtThreadIdToDrdThreadId
)(arg
[1]);
287 if (thread_to_join
== DRD_INVALID_THREADID
)
289 InvalidThreadIdInfo ITI
= { DRD_(thread_get_running_tid
)(), arg
[1] };
290 VG_(maybe_record_error
)(vg_tid
,
293 "pthread_join(): invalid thread ID",
298 DRD_(thread_post_join
)(drd_tid
, thread_to_join
);
303 case VG_USERREQ_DRD_PRE_THREAD_CANCEL
:
305 const DrdThreadId thread_to_cancel
=DRD_(PtThreadIdToDrdThreadId
)(arg
[1]);
306 if (thread_to_cancel
== DRD_INVALID_THREADID
)
308 InvalidThreadIdInfo ITI
= { DRD_(thread_get_running_tid
)(), arg
[1] };
309 VG_(maybe_record_error
)(vg_tid
,
312 "pthread_cancel(): invalid thread ID",
317 DRD_(thread_pre_cancel
)(thread_to_cancel
);
322 case VG_USERREQ_DRD_POST_THREAD_CANCEL
:
325 case VG_USERREQ_DRD_PRE_MUTEX_INIT
:
326 if (DRD_(thread_enter_synchr
)(drd_tid
) == 0)
327 DRD_(mutex_init
)(arg
[1], arg
[2]);
330 case VG_USERREQ_DRD_POST_MUTEX_INIT
:
331 DRD_(thread_leave_synchr
)(drd_tid
);
334 case VG_USERREQ_DRD_PRE_MUTEX_DESTROY
:
335 DRD_(thread_enter_synchr
)(drd_tid
);
338 case VG_USERREQ_DRD_POST_MUTEX_DESTROY
:
339 if (DRD_(thread_leave_synchr
)(drd_tid
) == 0)
340 DRD_(mutex_post_destroy
)(arg
[1]);
343 case VG_USERREQ_DRD_PRE_MUTEX_LOCK
:
344 if (DRD_(thread_enter_synchr
)(drd_tid
) == 0)
345 DRD_(mutex_pre_lock
)(arg
[1], arg
[2], arg
[3]);
348 case VG_USERREQ_DRD_POST_MUTEX_LOCK
:
349 if (DRD_(thread_leave_synchr
)(drd_tid
) == 0)
350 DRD_(mutex_post_lock
)(arg
[1], arg
[2], False
/*post_cond_wait*/);
353 case VG_USERREQ_DRD_PRE_MUTEX_UNLOCK
:
354 if (DRD_(thread_enter_synchr
)(drd_tid
) == 0)
355 DRD_(mutex_unlock
)(arg
[1], arg
[2]);
358 case VG_USERREQ_DRD_POST_MUTEX_UNLOCK
:
359 DRD_(thread_leave_synchr
)(drd_tid
);
362 case VG_USERREQ__DRD_IGNORE_MUTEX_ORDERING
:
363 DRD_(mutex_ignore_ordering
)(arg
[1]);
366 case VG_USERREQ_DRD_PRE_SPIN_INIT_OR_UNLOCK
:
367 if (DRD_(thread_enter_synchr
)(drd_tid
) == 0)
368 DRD_(spinlock_init_or_unlock
)(arg
[1]);
371 case VG_USERREQ_DRD_POST_SPIN_INIT_OR_UNLOCK
:
372 DRD_(thread_leave_synchr
)(drd_tid
);
375 case VG_USERREQ_DRD_PRE_COND_INIT
:
376 if (DRD_(thread_enter_synchr
)(drd_tid
) == 0)
377 DRD_(cond_pre_init
)(arg
[1]);
380 case VG_USERREQ_DRD_POST_COND_INIT
:
381 DRD_(thread_leave_synchr
)(drd_tid
);
384 case VG_USERREQ_DRD_PRE_COND_DESTROY
:
385 DRD_(thread_enter_synchr
)(drd_tid
);
388 case VG_USERREQ_DRD_POST_COND_DESTROY
:
389 if (DRD_(thread_leave_synchr
)(drd_tid
) == 0)
390 DRD_(cond_post_destroy
)(arg
[1], arg
[2]);
393 case VG_USERREQ_DRD_PRE_COND_WAIT
:
394 if (DRD_(thread_enter_synchr
)(drd_tid
) == 0)
396 const Addr cond
= arg
[1];
397 const Addr mutex
= arg
[2];
398 const MutexT mutex_type
= arg
[3];
399 DRD_(mutex_unlock
)(mutex
, mutex_type
);
400 DRD_(cond_pre_wait
)(cond
, mutex
);
404 case VG_USERREQ_DRD_POST_COND_WAIT
:
405 if (DRD_(thread_leave_synchr
)(drd_tid
) == 0)
407 const Addr cond
= arg
[1];
408 const Addr mutex
= arg
[2];
409 const Bool took_lock
= arg
[3];
410 DRD_(cond_post_wait
)(cond
);
411 DRD_(mutex_post_lock
)(mutex
, took_lock
, True
);
415 case VG_USERREQ_DRD_PRE_COND_SIGNAL
:
416 if (DRD_(thread_enter_synchr
)(drd_tid
) == 0)
417 DRD_(cond_pre_signal
)(arg
[1]);
420 case VG_USERREQ_DRD_POST_COND_SIGNAL
:
421 DRD_(thread_leave_synchr
)(drd_tid
);
424 case VG_USERREQ_DRD_PRE_COND_BROADCAST
:
425 if (DRD_(thread_enter_synchr
)(drd_tid
) == 0)
426 DRD_(cond_pre_broadcast
)(arg
[1]);
429 case VG_USERREQ_DRD_POST_COND_BROADCAST
:
430 DRD_(thread_leave_synchr
)(drd_tid
);
433 case VG_USERREQ_DRD_PRE_SEM_INIT
:
434 if (DRD_(thread_enter_synchr
)(drd_tid
) == 0)
435 DRD_(semaphore_init
)(arg
[1], arg
[2], arg
[3]);
438 case VG_USERREQ_DRD_POST_SEM_INIT
:
439 DRD_(thread_leave_synchr
)(drd_tid
);
442 case VG_USERREQ_DRD_PRE_SEM_DESTROY
:
443 DRD_(thread_enter_synchr
)(drd_tid
);
446 case VG_USERREQ_DRD_POST_SEM_DESTROY
:
447 if (DRD_(thread_leave_synchr
)(drd_tid
) == 0)
448 DRD_(semaphore_destroy
)(arg
[1]);
451 case VG_USERREQ_DRD_PRE_SEM_OPEN
:
452 DRD_(thread_enter_synchr
)(drd_tid
);
455 case VG_USERREQ_DRD_POST_SEM_OPEN
:
456 if (DRD_(thread_leave_synchr
)(drd_tid
) == 0)
457 DRD_(semaphore_open
)(arg
[1], (HChar
*)arg
[2], arg
[3], arg
[4], arg
[5]);
460 case VG_USERREQ_DRD_PRE_SEM_CLOSE
:
461 if (DRD_(thread_enter_synchr
)(drd_tid
) == 0)
462 DRD_(semaphore_close
)(arg
[1]);
465 case VG_USERREQ_DRD_POST_SEM_CLOSE
:
466 DRD_(thread_leave_synchr
)(drd_tid
);
469 case VG_USERREQ_DRD_PRE_SEM_WAIT
:
470 if (DRD_(thread_enter_synchr
)(drd_tid
) == 0)
471 DRD_(semaphore_pre_wait
)(arg
[1]);
474 case VG_USERREQ_DRD_POST_SEM_WAIT
:
475 if (DRD_(thread_leave_synchr
)(drd_tid
) == 0)
476 DRD_(semaphore_post_wait
)(drd_tid
, arg
[1], arg
[2]);
479 case VG_USERREQ_DRD_PRE_SEM_POST
:
480 if (DRD_(thread_enter_synchr
)(drd_tid
) == 0)
481 DRD_(semaphore_pre_post
)(drd_tid
, arg
[1]);
484 case VG_USERREQ_DRD_POST_SEM_POST
:
485 if (DRD_(thread_leave_synchr
)(drd_tid
) == 0)
486 DRD_(semaphore_post_post
)(drd_tid
, arg
[1], arg
[2]);
489 case VG_USERREQ_DRD_PRE_BARRIER_INIT
:
490 if (DRD_(thread_enter_synchr
)(drd_tid
) == 0)
491 DRD_(barrier_init
)(arg
[1], arg
[2], arg
[3], arg
[4]);
494 case VG_USERREQ_DRD_POST_BARRIER_INIT
:
495 DRD_(thread_leave_synchr
)(drd_tid
);
498 case VG_USERREQ_DRD_PRE_BARRIER_DESTROY
:
499 DRD_(thread_enter_synchr
)(drd_tid
);
502 case VG_USERREQ_DRD_POST_BARRIER_DESTROY
:
503 if (DRD_(thread_leave_synchr
)(drd_tid
) == 0)
504 DRD_(barrier_destroy
)(arg
[1], arg
[2]);
507 case VG_USERREQ_DRD_PRE_BARRIER_WAIT
:
508 if (DRD_(thread_enter_synchr
)(drd_tid
) == 0)
509 DRD_(barrier_pre_wait
)(drd_tid
, arg
[1], arg
[2]);
512 case VG_USERREQ_DRD_POST_BARRIER_WAIT
:
513 if (DRD_(thread_leave_synchr
)(drd_tid
) == 0)
514 DRD_(barrier_post_wait
)(drd_tid
, arg
[1], arg
[2], arg
[3], arg
[4]);
517 case VG_USERREQ_DRD_PRE_RWLOCK_INIT
:
518 if (DRD_(thread_enter_synchr
)(drd_tid
) == 0)
519 DRD_(rwlock_pre_init
)(arg
[1], pthread_rwlock
);
522 case VG_USERREQ_DRD_POST_RWLOCK_INIT
:
523 DRD_(thread_leave_synchr
)(drd_tid
);
526 case VG_USERREQ_DRD_PRE_RWLOCK_DESTROY
:
527 DRD_(thread_enter_synchr
)(drd_tid
);
530 case VG_USERREQ_DRD_POST_RWLOCK_DESTROY
:
531 if (DRD_(thread_leave_synchr
)(drd_tid
) == 0)
532 DRD_(rwlock_post_destroy
)(arg
[1], pthread_rwlock
);
535 case VG_USERREQ_DRD_PRE_RWLOCK_RDLOCK
:
536 if (DRD_(thread_enter_synchr
)(drd_tid
) == 0)
537 DRD_(rwlock_pre_rdlock
)(arg
[1], pthread_rwlock
);
540 case VG_USERREQ_DRD_POST_RWLOCK_RDLOCK
:
541 if (DRD_(thread_leave_synchr
)(drd_tid
) == 0)
542 DRD_(rwlock_post_rdlock
)(arg
[1], pthread_rwlock
, arg
[2]);
545 case VG_USERREQ_DRD_PRE_RWLOCK_WRLOCK
:
546 if (DRD_(thread_enter_synchr
)(drd_tid
) == 0)
547 DRD_(rwlock_pre_wrlock
)(arg
[1], pthread_rwlock
);
550 case VG_USERREQ_DRD_POST_RWLOCK_WRLOCK
:
551 if (DRD_(thread_leave_synchr
)(drd_tid
) == 0)
552 DRD_(rwlock_post_wrlock
)(arg
[1], pthread_rwlock
, arg
[2]);
555 case VG_USERREQ_DRD_PRE_RWLOCK_UNLOCK
:
556 if (DRD_(thread_enter_synchr
)(drd_tid
) == 0)
557 DRD_(rwlock_pre_unlock
)(arg
[1], pthread_rwlock
);
560 case VG_USERREQ_DRD_POST_RWLOCK_UNLOCK
:
561 DRD_(thread_leave_synchr
)(drd_tid
);
564 case VG_USERREQ__DRD_CLEAN_MEMORY
:
566 DRD_(clean_memory
)(arg
[1], arg
[2]);
569 case VG_USERREQ__HELGRIND_ANNOTATION_UNIMP
:
571 /* Note: it is assumed below that the text arg[1] points to is never
572 * freed, e.g. because it points to static data.
574 UnimpClReqInfo UICR
=
575 { DRD_(thread_get_running_tid
)(), (HChar
*)arg
[1] };
576 VG_(maybe_record_error
)(vg_tid
,
584 case VG_USERREQ__DRD_ANNOTATION_UNIMP
:
586 /* Note: it is assumed below that the text arg[1] points to is never
587 * freed, e.g. because it points to static data.
589 UnimpClReqInfo UICR
=
590 { DRD_(thread_get_running_tid
)(), (HChar
*)arg
[1] };
591 VG_(maybe_record_error
)(vg_tid
,
599 #if defined(VGO_solaris)
600 case VG_USERREQ_DRD_RTLD_BIND_GUARD
:
601 DRD_(thread_entering_rtld_bind_guard
)(drd_tid
, arg
[1]);
604 case VG_USERREQ_DRD_RTLD_BIND_CLEAR
:
605 DRD_(thread_leaving_rtld_bind_clear
)(drd_tid
, arg
[1]);
607 #endif /* VGO_solaris */
610 if (VG_IS_TOOL_USERREQ('D','R',arg
[0]) ||
611 VG_IS_TOOL_USERREQ('D','r',arg
[0])) {
612 /* don't warn about any unhandled HG client reqs */
613 VG_(message
)(Vg_UserMsg
,
614 "Warning: unknown DRD client request code %llx\n",
625 * DRD's handler for Valgrind client requests. The code below handles both
626 * DRD's public and tool-internal client requests.
628 static Bool
handle_client_request(ThreadId vg_tid
, UWord
* arg
, UWord
* ret
)
630 if (VG_IS_TOOL_USERREQ(0, 0, arg
[0]))
631 return handle_core_client_request(vg_tid
, arg
, ret
);
633 if (VG_IS_TOOL_USERREQ('D', 'R', arg
[0]) ||
634 VG_IS_TOOL_USERREQ('D', 'r', arg
[0]) ||
635 VG_IS_TOOL_USERREQ('H', 'G', arg
[0]))
636 return handle_thr_client_request(vg_tid
, arg
, ret
);
642 * Tell the Valgrind core the address of the DRD function that processes
643 * client requests. Must be called before any client code is run.
645 void DRD_(clientreq_init
)(void)
647 VG_(needs_client_requests
)(handle_client_request
);