1 /* 2 This file is part of drd, a thread error detector. 3 4 Copyright (C) 2006-2012 Bart Van Assche <bvanassche (at) 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 */ 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 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