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 (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_clientobj.h" /* struct mutex_info */ 27 #include "drd_error.h" 28 #include "drd_malloc_wrappers.h" 29 #include "drd_mutex.h" 30 #include "drd_suppression.h" /* drd_start_suppression() */ 31 #include "pub_drd_bitmap.h" /* LHS_W, ... */ 32 #include "pub_tool_vki.h" 33 #include "pub_tool_basics.h" 34 #include "pub_tool_libcassert.h" /* tl_assert() */ 35 #include "pub_tool_libcbase.h" /* strlen() */ 36 #include "pub_tool_libcfile.h" /* VG_(get_startup_wd)() */ 37 #include "pub_tool_libcprint.h" /* VG_(printf)() */ 38 #include "pub_tool_machine.h" 39 #include "pub_tool_mallocfree.h" /* VG_(malloc), VG_(free) */ 40 #include "pub_tool_options.h" /* VG_(clo_xml) */ 41 #include "pub_tool_threadstate.h" /* VG_(get_pthread_id)() */ 42 #include "pub_tool_tooliface.h" /* VG_(needs_tool_errors)() */ 43 44 45 /* Local function declarations. */ 46 47 static Char* drd_get_error_name(Error* e); 48 49 50 /* Local variables. */ 51 52 static Bool s_show_conflicting_segments = True; 53 54 55 void DRD_(set_show_conflicting_segments)(const Bool scs) 56 { 57 s_show_conflicting_segments = scs; 58 } 59 60 void DRD_(trace_msg)(const char* format, ...) 61 { 62 va_list vargs; 63 va_start(vargs, format); 64 if (VG_(clo_xml)) { 65 VG_(printf_xml)(" <trace><text>"); 66 VG_(vprintf_xml)(format, vargs); 67 VG_(printf_xml)("</text></trace>\n"); 68 } else { 69 VG_(vmessage)(Vg_UserMsg, format, vargs); 70 VG_(message)(Vg_UserMsg, "\n"); 71 } 72 va_end(vargs); 73 } 74 75 void DRD_(trace_msg_w_bt)(const char* format, ...) 76 { 77 va_list vargs; 78 va_start(vargs, format); 79 if (VG_(clo_xml)) { 80 VG_(printf_xml)(" <trace><text>"); 81 VG_(vprintf_xml)(format, vargs); 82 VG_(printf_xml)("</text>\n"); 83 } else { 84 VG_(vmessage)(Vg_UserMsg, format, vargs); 85 VG_(message)(Vg_UserMsg, "\n"); 86 } 87 VG_(get_and_pp_StackTrace)(VG_(get_running_tid)(), VG_(clo_backtrace_size)); 88 va_end(vargs); 89 if (VG_(clo_xml)) 90 VG_(printf_xml)(" </trace>\n"); 91 } 92 93 /** 94 * Emit error message detail in the format requested by the user. 95 */ 96 static void print_err_detail(const char* format, ...) PRINTF_CHECK(1, 2); 97 static void print_err_detail(const char* format, ...) 98 { 99 va_list vargs; 100 va_start(vargs, format); 101 if (VG_(clo_xml)) 102 VG_(vprintf_xml)(format, vargs); 103 else 104 VG_(vmessage)(Vg_UserMsg, format, vargs); 105 va_end(vargs); 106 } 107 108 /** 109 * Describe the client address a as good as possible, putting the result in ai. 110 */ 111 static 112 void describe_malloced_addr(Addr const a, AddrInfo* const ai) 113 { 114 Addr heap_block_start; 115 116 if (DRD_(heap_addrinfo)(a, &heap_block_start, &ai->size, &ai->lastchange)) 117 { 118 ai->akind = eMallocd; 119 ai->rwoffset = a - heap_block_start; 120 } 121 else 122 { 123 ai->akind = eUnknown; 124 } 125 } 126 127 /** 128 * Report where a client synchronization object has been observed for the first 129 * time. The printed call stack will either refer to a pthread_*_init() or a 130 * pthread_*lock() call. 131 */ 132 static void first_observed(const Addr obj) 133 { 134 DrdClientobj* cl; 135 136 cl = DRD_(clientobj_get_any)(obj); 137 if (cl) { 138 tl_assert(cl->any.first_observed_at); 139 if (VG_(clo_xml)) { 140 print_err_detail(" <first_observed_at>\n" 141 " <what>%pS</what>\n" 142 " <address>0x%lx</address>\n", 143 DRD_(clientobj_type_name)(cl->any.type), obj); 144 VG_(pp_ExeContext)(cl->any.first_observed_at); 145 print_err_detail(" </first_observed_at>\n"); 146 } else { 147 print_err_detail("%s 0x%lx was first observed at:\n", 148 DRD_(clientobj_type_name)(cl->any.type), obj); 149 VG_(pp_ExeContext)(cl->any.first_observed_at); 150 } 151 } 152 } 153 154 static 155 void drd_report_data_race(Error* const err, const DataRaceErrInfo* const dri) 156 { 157 const Bool xml = VG_(clo_xml); 158 const char* const what_prefix = xml ? " <what>" : ""; 159 const char* const what_suffix = xml ? "</what>" : ""; 160 const char* const auxwhat_prefix = xml ? " <auxwhat>" : ""; 161 const char* const auxwhat_suffix = xml ? "</auxwhat>" : ""; 162 const char* const indent = xml ? " " : ""; 163 AddrInfo ai; 164 165 XArray* /* of HChar */ descr1 166 = VG_(newXA)( VG_(malloc), "drd.error.drdr2.1", 167 VG_(free), sizeof(HChar) ); 168 XArray* /* of HChar */ descr2 169 = VG_(newXA)( VG_(malloc), "drd.error.drdr2.2", 170 VG_(free), sizeof(HChar) ); 171 172 tl_assert(dri); 173 tl_assert(dri->addr); 174 tl_assert(dri->size > 0); 175 tl_assert(descr1); 176 tl_assert(descr2); 177 178 (void) VG_(get_data_description)(descr1, descr2, dri->addr); 179 /* If there's nothing in descr1/2, free them. Why is it safe to to 180 VG_(indexXA) at zero here? Because VG_(get_data_description) 181 guarantees to zero terminate descr1/2 regardless of the outcome 182 of the call. So there's always at least one element in each XA 183 after the call. 184 */ 185 if (0 == VG_(strlen)( VG_(indexXA)( descr1, 0 ))) { 186 VG_(deleteXA)( descr1 ); 187 descr1 = NULL; 188 } 189 if (0 == VG_(strlen)( VG_(indexXA)( descr2, 0 ))) { 190 VG_(deleteXA)( descr2 ); 191 descr2 = NULL; 192 } 193 /* Assume (assert) that VG_(get_data_description) fills in descr1 194 before it fills in descr2 */ 195 if (descr1 == NULL) 196 tl_assert(descr2 == NULL); 197 /* So anyway. Do we have something useful? */ 198 if (descr1 == NULL) 199 { 200 /* No. Do Plan B. */ 201 describe_malloced_addr(dri->addr, &ai); 202 } 203 204 print_err_detail("%sConflicting %s by thread %d at 0x%08lx size %ld%s\n", 205 what_prefix, dri->access_type == eStore ? "store" : "load", 206 dri->tid, dri->addr, dri->size, what_suffix); 207 208 VG_(pp_ExeContext)(VG_(get_error_where)(err)); 209 if (descr1 != NULL) { 210 print_err_detail("%s%s\n", indent, (HChar*)VG_(indexXA)(descr1, 0)); 211 if (descr2 != NULL) 212 print_err_detail("%s%s\n", indent, (HChar*)VG_(indexXA)(descr2, 0)); 213 } else if (ai.akind == eMallocd && ai.lastchange) { 214 print_err_detail("%sAddress 0x%lx is at offset %ld from 0x%lx.%s%s", 215 auxwhat_prefix, dri->addr, ai.rwoffset, 216 dri->addr - ai.rwoffset, auxwhat_suffix, 217 xml ? "\n" : ""); 218 if (xml) 219 print_err_detail(" <allocation_context>\n"); 220 else 221 print_err_detail(" Allocation context:\n"); 222 VG_(pp_ExeContext)(ai.lastchange); 223 if (xml) 224 print_err_detail(" </allocation_context>\n"); 225 } else { 226 char sect_name[64]; 227 VgSectKind sect_kind; 228 229 sect_kind = VG_(DebugInfo_sect_kind)(sect_name, sizeof(sect_name), 230 dri->addr); 231 if (sect_kind != Vg_SectUnknown) { 232 print_err_detail("%sAllocation context: %ps section of %ps%s\n", 233 auxwhat_prefix, VG_(pp_SectKind)(sect_kind), 234 sect_name, auxwhat_suffix); 235 } else { 236 print_err_detail("%sAllocation context: unknown.%s\n", 237 auxwhat_prefix, auxwhat_suffix); 238 } 239 } 240 if (s_show_conflicting_segments) 241 { 242 DRD_(thread_report_conflicting_segments)(dri->tid, 243 dri->addr, dri->size, 244 dri->access_type); 245 } 246 247 if (descr2) 248 VG_(deleteXA)(descr2); 249 if (descr1) 250 VG_(deleteXA)(descr1); 251 } 252 253 /** 254 * Compare two error contexts. The core function VG_(maybe_record_error)() 255 * calls this function to compare error contexts such that errors that occur 256 * repeatedly are only printed once. This function is only called by the core 257 * if the error kind of e1 and e2 matches and if the ExeContext's of e1 and 258 * e2 also match. 259 */ 260 static Bool drd_compare_error_contexts(VgRes res, Error* e1, Error* e2) 261 { 262 tl_assert(VG_(get_error_kind)(e1) == VG_(get_error_kind)(e2)); 263 264 switch (VG_(get_error_kind)(e1)) 265 { 266 case DataRaceErr: 267 { 268 const DataRaceErrInfo* const dri1 = VG_(get_error_extra)(e1); 269 const DataRaceErrInfo* const dri2 = VG_(get_error_extra)(e2); 270 return dri1->access_type == dri2->access_type 271 && dri1->size == dri2->size; 272 } 273 case MutexErr: 274 { 275 const MutexErrInfo* const mei1 = VG_(get_error_extra)(e1); 276 const MutexErrInfo* const mei2 = VG_(get_error_extra)(e2); 277 return mei1->mutex == mei2->mutex; 278 } 279 default: 280 return True; 281 } 282 } 283 284 /** 285 * Called by the core just before an error message will be printed. Used by 286 * DRD to print the thread number as a preamble. 287 */ 288 static void drd_tool_error_before_pp(Error* const e) 289 { 290 static DrdThreadId s_last_tid_printed = 1; 291 DrdThreadId* err_extra; 292 293 err_extra = VG_(get_error_extra)(e); 294 295 if (err_extra && *err_extra != s_last_tid_printed && !VG_(clo_xml)) { 296 VG_(umsg)("%s:\n", DRD_(thread_get_name)(*err_extra)); 297 s_last_tid_printed = *err_extra; 298 } 299 } 300 301 /** Report an error to the user. */ 302 static void drd_tool_error_pp(Error* const e) 303 { 304 const Bool xml = VG_(clo_xml); 305 const char* const what_prefix = xml ? " <what>" : ""; 306 const char* const what_suffix = xml ? "</what>" : ""; 307 308 if (xml) 309 VG_(printf_xml)( " <kind>%pS</kind>\n", drd_get_error_name(e)); 310 311 switch (VG_(get_error_kind)(e)) 312 { 313 case DataRaceErr: { 314 drd_report_data_race(e, VG_(get_error_extra)(e)); 315 break; 316 } 317 case MutexErr: { 318 MutexErrInfo* p = (MutexErrInfo*)(VG_(get_error_extra)(e)); 319 tl_assert(p); 320 if (p->recursion_count >= 0) { 321 print_err_detail("%s%s: mutex 0x%lx, recursion count %d, owner %d." 322 "%s\n", what_prefix, VG_(get_error_string)(e), 323 p->mutex, p->recursion_count, p->owner, what_suffix); 324 } else { 325 print_err_detail("%sThe object at address 0x%lx is not a mutex.%s\n", 326 what_prefix, p->mutex, what_suffix); 327 } 328 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 329 first_observed(p->mutex); 330 break; 331 } 332 case CondErr: { 333 CondErrInfo* cdei =(CondErrInfo*)(VG_(get_error_extra)(e)); 334 print_err_detail("%s%s: cond 0x%lx%s\n", what_prefix, 335 VG_(get_error_string)(e), cdei->cond, what_suffix); 336 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 337 first_observed(cdei->cond); 338 break; 339 } 340 case CondDestrErr: { 341 CondDestrErrInfo* cdi = (CondDestrErrInfo*)(VG_(get_error_extra)(e)); 342 print_err_detail("%s%s: cond 0x%lx, mutex 0x%lx locked by thread %d%s\n", 343 what_prefix, VG_(get_error_string)(e), cdi->cond, 344 cdi->mutex, cdi->owner, what_suffix); 345 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 346 first_observed(cdi->mutex); 347 break; 348 } 349 case CondRaceErr: { 350 CondRaceErrInfo* cei = (CondRaceErrInfo*)(VG_(get_error_extra)(e)); 351 print_err_detail("%sProbably a race condition: condition variable 0x%lx" 352 " has been signaled but the associated mutex 0x%lx is" 353 " not locked by the signalling thread.%s\n", 354 what_prefix, cei->cond, cei->mutex, what_suffix); 355 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 356 first_observed(cei->cond); 357 first_observed(cei->mutex); 358 break; 359 } 360 case CondWaitErr: { 361 CondWaitErrInfo* cwei = (CondWaitErrInfo*)(VG_(get_error_extra)(e)); 362 print_err_detail("%s%s: condition variable 0x%lx, mutexes 0x%lx and" 363 " 0x%lx%s\n", what_prefix, VG_(get_error_string)(e), 364 cwei->cond, cwei->mutex1, cwei->mutex2, what_suffix); 365 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 366 first_observed(cwei->cond); 367 first_observed(cwei->mutex1); 368 first_observed(cwei->mutex2); 369 break; 370 } 371 case SemaphoreErr: { 372 SemaphoreErrInfo* sei = (SemaphoreErrInfo*)(VG_(get_error_extra)(e)); 373 tl_assert(sei); 374 print_err_detail("%s%s: semaphore 0x%lx%s\n", what_prefix, 375 VG_(get_error_string)(e), sei->semaphore, what_suffix); 376 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 377 first_observed(sei->semaphore); 378 break; 379 } 380 case BarrierErr: { 381 BarrierErrInfo* bei = (BarrierErrInfo*)(VG_(get_error_extra)(e)); 382 tl_assert(bei); 383 print_err_detail("%s%s: barrier 0x%lx%s\n", what_prefix, 384 VG_(get_error_string)(e), bei->barrier, what_suffix); 385 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 386 if (bei->other_context) { 387 if (xml) 388 print_err_detail(" <confl_wait_call>\n"); 389 print_err_detail("%sConflicting wait call by thread %d:%s\n", 390 what_prefix, bei->other_tid, what_suffix); 391 VG_(pp_ExeContext)(bei->other_context); 392 if (xml) 393 print_err_detail(" </confl_wait_call>\n"); 394 } 395 first_observed(bei->barrier); 396 break; 397 } 398 case RwlockErr: { 399 RwlockErrInfo* p = (RwlockErrInfo*)(VG_(get_error_extra)(e)); 400 tl_assert(p); 401 print_err_detail("%s%s: rwlock 0x%lx.%s\n", what_prefix, 402 VG_(get_error_string)(e), p->rwlock, what_suffix); 403 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 404 first_observed(p->rwlock); 405 break; 406 } 407 case HoldtimeErr: { 408 HoldtimeErrInfo* p =(HoldtimeErrInfo*)(VG_(get_error_extra)(e)); 409 tl_assert(p); 410 tl_assert(p->acquired_at); 411 if (xml) 412 print_err_detail(" <acquired_at>\n"); 413 else 414 print_err_detail("Acquired at:\n"); 415 VG_(pp_ExeContext)(p->acquired_at); 416 if (xml) 417 print_err_detail(" </acquired_at>\n"); 418 print_err_detail("%sLock on %s 0x%lx was held during %d ms" 419 " (threshold: %d ms).%s\n", what_prefix, 420 VG_(get_error_string)(e), p->synchronization_object, 421 p->hold_time_ms, p->threshold_ms, what_suffix); 422 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 423 first_observed(p->synchronization_object); 424 break; 425 } 426 case GenericErr: { 427 GenericErrInfo* gei = (GenericErrInfo*)(VG_(get_error_extra)(e)); 428 print_err_detail("%s%s%s\n", what_prefix, VG_(get_error_string)(e), 429 what_suffix); 430 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 431 if (gei->addr) 432 first_observed(gei->addr); 433 break; 434 } 435 case InvalidThreadId: { 436 InvalidThreadIdInfo* iti =(InvalidThreadIdInfo*)(VG_(get_error_extra)(e)); 437 print_err_detail("%s%s 0x%llx%s\n", what_prefix, VG_(get_error_string)(e), 438 iti->ptid, what_suffix); 439 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 440 break; 441 } 442 case UnimpHgClReq: { 443 UnimpClReqInfo* uicr =(UnimpClReqInfo*)(VG_(get_error_extra)(e)); 444 print_err_detail("%sThe annotation macro %s has not yet been implemented" 445 " in %ps%s\n", what_prefix, uicr->descr, 446 "<valgrind/helgrind.h>", what_suffix); 447 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 448 break; 449 } 450 case UnimpDrdClReq: { 451 UnimpClReqInfo* uicr =(UnimpClReqInfo*)(VG_(get_error_extra)(e)); 452 print_err_detail("%sThe annotation macro %s has not yet been implemented" 453 " in %ps%s\n", what_prefix, uicr->descr, 454 "<valgrind/drd.h>", what_suffix); 455 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 456 break; 457 } 458 default: 459 print_err_detail("%s%s%s\n", what_prefix, VG_(get_error_string)(e), 460 what_suffix); 461 VG_(pp_ExeContext)(VG_(get_error_where)(e)); 462 break; 463 } 464 } 465 466 static UInt drd_tool_error_update_extra(Error* e) 467 { 468 switch (VG_(get_error_kind)(e)) 469 { 470 case DataRaceErr: 471 return sizeof(DataRaceErrInfo); 472 case MutexErr: 473 return sizeof(MutexErrInfo); 474 case CondErr: 475 return sizeof(CondErrInfo); 476 case CondDestrErr: 477 return sizeof(CondDestrErrInfo); 478 case CondRaceErr: 479 return sizeof(CondRaceErrInfo); 480 case CondWaitErr: 481 return sizeof(CondWaitErrInfo); 482 case SemaphoreErr: 483 return sizeof(SemaphoreErrInfo); 484 case BarrierErr: 485 return sizeof(BarrierErrInfo); 486 case RwlockErr: 487 return sizeof(RwlockErrInfo); 488 case HoldtimeErr: 489 return sizeof(HoldtimeErrInfo); 490 case GenericErr: 491 return sizeof(GenericErrInfo); 492 case InvalidThreadId: 493 return sizeof(InvalidThreadIdInfo); 494 case UnimpHgClReq: 495 return sizeof(UnimpClReqInfo); 496 case UnimpDrdClReq: 497 return sizeof(UnimpClReqInfo); 498 default: 499 tl_assert(False); 500 break; 501 } 502 } 503 504 /** 505 * Parse suppression name. 506 * 507 * The suppression types recognized by DRD are the same types as the error 508 * types supported by DRD. So try to match the suppression name against the 509 * names of DRD error types. 510 */ 511 static Bool drd_is_recognized_suppression(Char* const name, Supp* const supp) 512 { 513 DrdErrorKind skind = 0; 514 515 if (VG_(strcmp)(name, STR_DataRaceErr) == 0) 516 skind = DataRaceErr; 517 else if (VG_(strcmp)(name, STR_MutexErr) == 0) 518 skind = MutexErr; 519 else if (VG_(strcmp)(name, STR_CondErr) == 0) 520 skind = CondErr; 521 else if (VG_(strcmp)(name, STR_CondDestrErr) == 0) 522 skind = CondDestrErr; 523 else if (VG_(strcmp)(name, STR_CondRaceErr) == 0) 524 skind = CondRaceErr; 525 else if (VG_(strcmp)(name, STR_CondWaitErr) == 0) 526 skind = CondWaitErr; 527 else if (VG_(strcmp)(name, STR_SemaphoreErr) == 0) 528 skind = SemaphoreErr; 529 else if (VG_(strcmp)(name, STR_BarrierErr) == 0) 530 skind = BarrierErr; 531 else if (VG_(strcmp)(name, STR_RwlockErr) == 0) 532 skind = RwlockErr; 533 else if (VG_(strcmp)(name, STR_HoldtimeErr) == 0) 534 skind = HoldtimeErr; 535 else if (VG_(strcmp)(name, STR_GenericErr) == 0) 536 skind = GenericErr; 537 else if (VG_(strcmp)(name, STR_InvalidThreadId) == 0) 538 skind = InvalidThreadId; 539 else if (VG_(strcmp)(name, STR_UnimpHgClReq) == 0) 540 skind = UnimpHgClReq; 541 else if (VG_(strcmp)(name, STR_UnimpDrdClReq) == 0) 542 skind = UnimpDrdClReq; 543 else 544 return False; 545 546 VG_(set_supp_kind)(supp, skind); 547 return True; 548 } 549 550 /** 551 * Read additional suppression information from the suppression file. 552 * 553 * None of the suppression patterns recognized by DRD has 'extra' lines 554 * of information in the suppression file, so just return True to indicate 555 * that reading the 'extra' lines succeeded. 556 */ 557 static 558 Bool drd_read_extra_suppression_info(Int fd, Char** bufpp, 559 SizeT* nBufp, Supp* supp) 560 { 561 return True; 562 } 563 564 /** 565 * Determine whether or not the types of the given error message and the 566 * given suppression match. 567 */ 568 static Bool drd_error_matches_suppression(Error* const e, Supp* const supp) 569 { 570 return VG_(get_supp_kind)(supp) == VG_(get_error_kind)(e); 571 } 572 573 static Char* drd_get_error_name(Error* e) 574 { 575 switch (VG_(get_error_kind)(e)) 576 { 577 case DataRaceErr: return VGAPPEND(STR_, DataRaceErr); 578 case MutexErr: return VGAPPEND(STR_, MutexErr); 579 case CondErr: return VGAPPEND(STR_, CondErr); 580 case CondDestrErr: return VGAPPEND(STR_, CondDestrErr); 581 case CondRaceErr: return VGAPPEND(STR_, CondRaceErr); 582 case CondWaitErr: return VGAPPEND(STR_, CondWaitErr); 583 case SemaphoreErr: return VGAPPEND(STR_, SemaphoreErr); 584 case BarrierErr: return VGAPPEND(STR_, BarrierErr); 585 case RwlockErr: return VGAPPEND(STR_, RwlockErr); 586 case HoldtimeErr: return VGAPPEND(STR_, HoldtimeErr); 587 case GenericErr: return VGAPPEND(STR_, GenericErr); 588 case InvalidThreadId: return VGAPPEND(STR_, InvalidThreadId); 589 case UnimpHgClReq: return VGAPPEND(STR_, UnimpHgClReq); 590 case UnimpDrdClReq: return VGAPPEND(STR_, UnimpDrdClReq); 591 default: 592 tl_assert(0); 593 } 594 return 0; 595 } 596 597 /** 598 * Return extra suppression information. 599 * 600 * Invoked while printing a suppression pattern because the user 601 * specified --gen-suppressions=yes or all on the command line. DRD does not 602 * define any 'extra' suppression information. 603 */ 604 static 605 Bool drd_get_extra_suppression_info(Error* e, 606 /*OUT*/Char* buf, Int nBuf) 607 { 608 return False; 609 } 610 611 /** Tell the Valgrind core about DRD's error handlers. */ 612 void DRD_(register_error_handlers)(void) 613 { 614 VG_(needs_tool_errors)(drd_compare_error_contexts, 615 drd_tool_error_before_pp, 616 drd_tool_error_pp, 617 False, 618 drd_tool_error_update_extra, 619 drd_is_recognized_suppression, 620 drd_read_extra_suppression_info, 621 drd_error_matches_suppression, 622 drd_get_error_name, 623 drd_get_extra_suppression_info); 624 } 625