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 50Bool DRD_(g_free_is_write); 51 52 53/* Local function declarations. */ 54 55static 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 */ 64void 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 */ 73static 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