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