1 2 /*--------------------------------------------------------------------*/ 3 /*--- Management of error messages. m_errormgr.c ---*/ 4 /*--------------------------------------------------------------------*/ 5 6 /* 7 This file is part of Valgrind, a dynamic binary instrumentation 8 framework. 9 10 Copyright (C) 2000-2017 Julian Seward 11 jseward (at) acm.org 12 13 This program is free software; you can redistribute it and/or 14 modify it under the terms of the GNU General Public License as 15 published by the Free Software Foundation; either version 2 of the 16 License, or (at your option) any later version. 17 18 This program is distributed in the hope that it will be useful, but 19 WITHOUT ANY WARRANTY; without even the implied warranty of 20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21 General Public License for more details. 22 23 You should have received a copy of the GNU General Public License 24 along with this program; if not, write to the Free Software 25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 26 02111-1307, USA. 27 28 The GNU General Public License is contained in the file COPYING. 29 */ 30 31 #include "pub_core_basics.h" 32 #include "pub_core_vki.h" 33 #include "pub_core_threadstate.h" // For VG_N_THREADS 34 #include "pub_core_debuginfo.h" 35 #include "pub_core_debuglog.h" 36 #include "pub_core_errormgr.h" 37 #include "pub_core_execontext.h" 38 #include "pub_core_gdbserver.h" 39 #include "pub_core_libcbase.h" 40 #include "pub_core_libcassert.h" 41 #include "pub_core_libcfile.h" 42 #include "pub_core_libcprint.h" 43 #include "pub_core_libcproc.h" // For VG_(getpid)() 44 #include "pub_core_seqmatch.h" 45 #include "pub_core_mallocfree.h" 46 #include "pub_core_options.h" 47 #include "pub_core_stacktrace.h" 48 #include "pub_core_tooliface.h" 49 #include "pub_core_translate.h" // for VG_(translate)() 50 #include "pub_core_xarray.h" // VG_(xaprintf) et al 51 52 #define DEBUG_ERRORMGR 0 // set to 1 for heavyweight tracing 53 54 /*------------------------------------------------------------*/ 55 /*--- Globals ---*/ 56 /*------------------------------------------------------------*/ 57 58 /* After this many different unsuppressed errors have been observed, 59 be more conservative about collecting new ones. */ 60 #define M_COLLECT_ERRORS_SLOWLY_AFTER 100 61 62 /* After this many different unsuppressed errors have been observed, 63 stop collecting errors at all, and tell the user their program is 64 evidently a steaming pile of camel dung. */ 65 #define M_COLLECT_NO_ERRORS_AFTER_SHOWN 1000 66 67 /* After this many total errors have been observed, stop collecting 68 errors at all. Counterpart to M_COLLECT_NO_ERRORS_AFTER_SHOWN. */ 69 #define M_COLLECT_NO_ERRORS_AFTER_FOUND 10000000 70 71 /* The list of error contexts found, both suppressed and unsuppressed. 72 Initially empty, and grows as errors are detected. */ 73 static Error* errors = NULL; 74 75 /* The list of suppression directives, as read from the specified 76 suppressions file. Note that the list gets rearranged as a result 77 of the searches done by is_suppressible_error(). */ 78 static Supp* suppressions = NULL; 79 80 /* Running count of unsuppressed errors detected. */ 81 static UInt n_errs_found = 0; 82 83 /* Running count of suppressed errors detected. */ 84 static UInt n_errs_suppressed = 0; 85 86 /* Running count of errors shown. */ 87 static UInt n_errs_shown = 0; 88 89 /* Running count of unsuppressed error contexts. */ 90 static UInt n_err_contexts = 0; 91 92 /* Running count of suppressed error contexts. */ 93 static UInt n_supp_contexts = 0; 94 95 96 /* forwards ... */ 97 static Supp* is_suppressible_error ( const Error* err ); 98 99 static ThreadId last_tid_printed = 1; 100 101 /* Stats: number of searches of the error list initiated. */ 102 static UWord em_errlist_searches = 0; 103 104 /* Stats: number of comparisons done during error list 105 searching. */ 106 static UWord em_errlist_cmps = 0; 107 108 /* Stats: number of searches of the suppression list initiated. */ 109 static UWord em_supplist_searches = 0; 110 111 /* Stats: number of comparisons done during suppression list 112 searching. */ 113 static UWord em_supplist_cmps = 0; 114 115 /*------------------------------------------------------------*/ 116 /*--- Error type ---*/ 117 /*------------------------------------------------------------*/ 118 119 /* Errors. Extensible (via the 'extra' field). Tools can use a normal 120 enum (with element values in the normal range (0..)) for 'ekind'. 121 Functions for getting/setting the tool-relevant fields are in 122 include/pub_tool_errormgr.h. 123 124 When errors are found and recorded with VG_(maybe_record_error)(), all 125 the tool must do is pass in the four parameters; core will 126 allocate/initialise the error record. 127 */ 128 struct _Error { 129 struct _Error* next; 130 // Unique tag. This gives the error a unique identity (handle) by 131 // which it can be referred to afterwords. Currently only used for 132 // XML printing. 133 UInt unique; 134 // NULL if unsuppressed; or ptr to suppression record. 135 Supp* supp; 136 Int count; 137 138 // The tool-specific part 139 ThreadId tid; // Initialised by core 140 ExeContext* where; // Initialised by core 141 ErrorKind ekind; // Used by ALL. Must be in the range (0..) 142 Addr addr; // Used frequently 143 const HChar* string; // Used frequently 144 void* extra; // For any tool-specific extras 145 }; 146 147 148 ExeContext* VG_(get_error_where) ( const Error* err ) 149 { 150 return err->where; 151 } 152 153 ErrorKind VG_(get_error_kind) ( const Error* err ) 154 { 155 return err->ekind; 156 } 157 158 Addr VG_(get_error_address) ( const Error* err ) 159 { 160 return err->addr; 161 } 162 163 const HChar* VG_(get_error_string) ( const Error* err ) 164 { 165 return err->string; 166 } 167 168 void* VG_(get_error_extra) ( const Error* err ) 169 { 170 return err->extra; 171 } 172 173 UInt VG_(get_n_errs_found)( void ) 174 { 175 return n_errs_found; 176 } 177 178 UInt VG_(get_n_errs_shown)( void ) 179 { 180 return n_errs_shown; 181 } 182 183 /*------------------------------------------------------------*/ 184 /*--- Suppression type ---*/ 185 /*------------------------------------------------------------*/ 186 187 /* Note: it is imperative this doesn't overlap with (0..) at all, as tools 188 * effectively extend it by defining their own enums in the (0..) range. */ 189 typedef 190 enum { 191 // Nb: thread errors are a relic of the time when Valgrind's core 192 // could detect them. This example is left commented-out as an 193 // example should new core errors ever be added. 194 ThreadSupp = -1, /* Matches ThreadErr */ 195 } 196 CoreSuppKind; 197 198 /* Max number of callers for context in a suppression is 199 VG_DEEPEST_BACKTRACE. */ 200 201 /* For each caller specified for a suppression, record the nature of 202 the caller name. Not of interest to tools. */ 203 typedef 204 enum { 205 NoName, /* Error case */ 206 ObjName, /* Name is of an shared object file. */ 207 FunName, /* Name is of a function. */ 208 DotDotDot /* Frame-level wildcard */ 209 } 210 SuppLocTy; 211 212 typedef 213 struct { 214 SuppLocTy ty; 215 Bool name_is_simple_str; /* True if name is a string without 216 '?' and '*' wildcard characters. */ 217 HChar* name; /* NULL for NoName and DotDotDot */ 218 } 219 SuppLoc; 220 221 /* Suppressions. Tools can get/set tool-relevant parts with functions 222 declared in include/pub_tool_errormgr.h. Extensible via the 'extra' field. 223 Tools can use a normal enum (with element values in the normal range 224 (0..)) for 'skind'. */ 225 struct _Supp { 226 struct _Supp* next; 227 Int count; // The number of times this error has been suppressed. 228 HChar* sname; // The name by which the suppression is referred to. 229 230 // Index in VG_(clo_suppressions) giving filename from which suppression 231 // was read, and the lineno in this file where sname was read. 232 Int clo_suppressions_i; 233 Int sname_lineno; 234 235 // Length of 'callers' 236 Int n_callers; 237 // Array of callers, for matching stack traces. First one (name of fn 238 // where err occurs) is mandatory; rest are optional. 239 SuppLoc* callers; 240 241 /* The tool-specific part */ 242 SuppKind skind; // What kind of suppression. Must use the range (0..). 243 HChar* string; // String -- use is optional. NULL by default. 244 void* extra; // Anything else -- use is optional. NULL by default. 245 }; 246 247 SuppKind VG_(get_supp_kind) ( const Supp* su ) 248 { 249 return su->skind; 250 } 251 252 HChar* VG_(get_supp_string) ( const Supp* su ) 253 { 254 return su->string; 255 } 256 257 void* VG_(get_supp_extra) ( const Supp* su ) 258 { 259 return su->extra; 260 } 261 262 263 void VG_(set_supp_kind) ( Supp* su, SuppKind skind ) 264 { 265 su->skind = skind; 266 } 267 268 void VG_(set_supp_string) ( Supp* su, HChar* string ) 269 { 270 su->string = string; 271 } 272 273 void VG_(set_supp_extra) ( Supp* su, void* extra ) 274 { 275 su->extra = extra; 276 } 277 278 279 /*------------------------------------------------------------*/ 280 /*--- Helper fns ---*/ 281 /*------------------------------------------------------------*/ 282 283 // Only show core errors if the tool wants to, we're not running with -q, 284 // and were not outputting XML. 285 Bool VG_(showing_core_errors)(void) 286 { 287 return VG_(needs).core_errors && VG_(clo_verbosity) >= 1 && !VG_(clo_xml); 288 } 289 290 /* Compare errors, to detect duplicates. 291 */ 292 static Bool eq_Error ( VgRes res, const Error* e1, const Error* e2 ) 293 { 294 if (e1->ekind != e2->ekind) 295 return False; 296 if (!VG_(eq_ExeContext)(res, e1->where, e2->where)) 297 return False; 298 299 switch (e1->ekind) { 300 //(example code, see comment on CoreSuppKind above) 301 //case ThreadErr: 302 // vg_assert(VG_(needs).core_errors); 303 // return <something> 304 default: 305 if (VG_(needs).tool_errors) { 306 return VG_TDICT_CALL(tool_eq_Error, res, e1, e2); 307 } else { 308 VG_(printf)("\nUnhandled error type: %u. VG_(needs).tool_errors\n" 309 "probably needs to be set.\n", 310 (UInt)e1->ekind); 311 VG_(core_panic)("unhandled error type"); 312 } 313 } 314 } 315 316 317 /* Helper functions for suppression generation: print a single line of 318 a suppression pseudo-stack-trace, either in XML or text mode. It's 319 important that the behaviour of these two functions exactly 320 corresponds. 321 */ 322 #define ERRTXT_LEN 4096 323 324 static void printSuppForIp_XML(UInt n, Addr ip, void* uu_opaque) 325 { 326 const HChar *buf; 327 InlIPCursor* iipc = VG_(new_IIPC)(ip); 328 do { 329 if ( VG_(get_fnname_no_cxx_demangle) (ip, &buf, iipc) ) { 330 VG_(printf_xml)(" <sframe> <fun>%pS</fun> </sframe>\n", buf); 331 } else 332 if ( VG_(get_objname)(ip, &buf) ) { 333 VG_(printf_xml)(" <sframe> <obj>%pS</obj> </sframe>\n", buf); 334 } else { 335 VG_(printf_xml)(" <sframe> <obj>*</obj> </sframe>\n"); 336 } 337 } while (VG_(next_IIPC)(iipc)); 338 VG_(delete_IIPC)(iipc); 339 } 340 341 static void printSuppForIp_nonXML(UInt n, Addr ip, void* textV) 342 { 343 const HChar *buf; 344 XArray* /* of HChar */ text = (XArray*)textV; 345 InlIPCursor* iipc = VG_(new_IIPC)(ip); 346 do { 347 if ( VG_(get_fnname_no_cxx_demangle) (ip, &buf, iipc) ) { 348 VG_(xaprintf)(text, " fun:%s\n", buf); 349 } else 350 if ( VG_(get_objname)(ip, &buf) ) { 351 VG_(xaprintf)(text, " obj:%s\n", buf); 352 } else { 353 VG_(xaprintf)(text, " obj:*\n"); 354 } 355 } while (VG_(next_IIPC)(iipc)); 356 VG_(delete_IIPC)(iipc); 357 } 358 359 /* Generate a suppression for an error, either in text or XML mode. 360 */ 361 static void gen_suppression(const Error* err) 362 { 363 const HChar* name; 364 ExeContext* ec; 365 XArray* /* HChar */ text; 366 367 const HChar* dummy_name = "insert_a_suppression_name_here"; 368 369 vg_assert(err); 370 371 ec = VG_(get_error_where)(err); 372 vg_assert(ec); 373 374 name = VG_TDICT_CALL(tool_get_error_name, err); 375 if (NULL == name) { 376 VG_(umsg)("(%s does not allow error to be suppressed)\n", 377 VG_(details).name); 378 return; 379 } 380 381 /* In XML mode, we also need to print the plain text version of the 382 suppresion in a CDATA section. What that really means is, we 383 need to generate the plaintext version both in XML and text 384 mode. So generate it into TEXT. */ 385 text = VG_(newXA)( VG_(malloc), "errormgr.gen_suppression.1", 386 VG_(free), sizeof(HChar) ); 387 388 /* Ok. Generate the plain text version into TEXT. */ 389 VG_(xaprintf)(text, "{\n"); 390 VG_(xaprintf)(text, " <%s>\n", dummy_name); 391 VG_(xaprintf)(text, " %s:%s\n", VG_(details).name, name); 392 393 HChar *xtra = NULL; 394 SizeT xtra_size = 0; 395 SizeT num_written; 396 397 do { 398 xtra_size += 256; 399 xtra = VG_(realloc)("errormgr.gen_suppression.2", xtra,xtra_size); 400 num_written = VG_TDICT_CALL(tool_get_extra_suppression_info, 401 err, xtra, xtra_size); 402 } while (num_written == xtra_size); // resize buffer and retry 403 404 // Ensure buffer is properly terminated 405 vg_assert(xtra[num_written] == '\0'); 406 407 if (num_written) 408 VG_(xaprintf)(text, " %s\n", xtra); 409 410 // Print stack trace elements 411 UInt n_ips = VG_(get_ExeContext_n_ips)(ec); 412 vg_assert(n_ips > 0); 413 vg_assert(n_ips <= VG_DEEPEST_BACKTRACE); 414 VG_(apply_StackTrace)(printSuppForIp_nonXML, 415 text, 416 VG_(get_ExeContext_StackTrace)(ec), 417 n_ips); 418 419 VG_(xaprintf)(text, "}\n"); 420 // zero terminate 421 VG_(xaprintf)(text, "%c", (HChar)0 ); 422 // VG_(printf) of text 423 424 /* And now display it. */ 425 if (! VG_(clo_xml) ) { 426 427 // the simple case 428 VG_(printf)("%s", (HChar*) VG_(indexXA)(text, 0) ); 429 430 } else { 431 432 /* Now we have to print the XML directly. No need to go to the 433 effort of stuffing it in an XArray, since we won't need it 434 again. */ 435 VG_(printf_xml)(" <suppression>\n"); 436 VG_(printf_xml)(" <sname>%s</sname>\n", dummy_name); 437 VG_(printf_xml)( 438 " <skind>%pS:%pS</skind>\n", VG_(details).name, name); 439 if (num_written) 440 VG_(printf_xml)(" <skaux>%pS</skaux>\n", xtra); 441 442 // Print stack trace elements 443 VG_(apply_StackTrace)(printSuppForIp_XML, 444 NULL, 445 VG_(get_ExeContext_StackTrace)(ec), 446 VG_(get_ExeContext_n_ips)(ec)); 447 448 // And now the cdata bit 449 // XXX FIXME! properly handle the case where the raw text 450 // itself contains "]]>", as specified in Protocol 4. 451 VG_(printf_xml)(" <rawtext>\n"); 452 VG_(printf_xml)("<![CDATA[\n"); 453 VG_(printf_xml)("%s", (HChar*) VG_(indexXA)(text, 0) ); 454 VG_(printf_xml)("]]>\n"); 455 VG_(printf_xml)(" </rawtext>\n"); 456 VG_(printf_xml)(" </suppression>\n"); 457 458 } 459 460 VG_(deleteXA)(text); 461 VG_(free)(xtra); 462 } 463 464 465 /* Figure out if we want to perform a given action for this error, 466 possibly by asking the user. 467 */ 468 Bool VG_(is_action_requested) ( const HChar* action, Bool* clo ) 469 { 470 HChar ch, ch2; 471 Int res; 472 473 /* First off, we shouldn't be asking the user anything if 474 we're in XML mode. */ 475 if (VG_(clo_xml)) 476 return False; /* That's a Nein, oder Nay as they say down here in B-W */ 477 478 if (*clo == False) 479 return False; 480 481 VG_(umsg)("\n"); 482 483 again: 484 VG_(printf)( 485 "==%d== " 486 "---- %s ? --- [Return/N/n/Y/y/C/c] ---- ", 487 VG_(getpid)(), action 488 ); 489 490 res = VG_(read)(VG_(clo_input_fd), &ch, 1); 491 if (res != 1) goto ioerror; 492 /* res == 1 */ 493 if (ch == '\n') return False; 494 if (ch != 'N' && ch != 'n' && ch != 'Y' && ch != 'y' 495 && ch != 'C' && ch != 'c') goto again; 496 497 res = VG_(read)(VG_(clo_input_fd), &ch2, 1); 498 if (res != 1) goto ioerror; 499 if (ch2 != '\n') goto again; 500 501 /* No, don't want to do action. */ 502 if (ch == 'n' || ch == 'N') return False; 503 /* Yes, want to do action. */ 504 if (ch == 'y' || ch == 'Y') return True; 505 /* No, don't want to do action, and don't ask again either. */ 506 vg_assert(ch == 'c' || ch == 'C'); 507 508 ioerror: 509 *clo = False; 510 return False; 511 } 512 513 514 /* Do text-mode actions on error, that is, immediately after an error 515 is printed. These are: 516 * possibly, call the GDB server 517 * possibly, generate a suppression. 518 Note this should not be called in XML mode! 519 */ 520 static 521 void do_actions_on_error(const Error* err, Bool allow_db_attach) 522 { 523 Bool still_noisy = True; 524 525 /* if user wants to debug from a certain error nr, then wait for gdb/vgdb */ 526 if (VG_(clo_vgdb) != Vg_VgdbNo 527 && allow_db_attach 528 && VG_(dyn_vgdb_error) <= n_errs_shown) { 529 VG_(umsg)("(action on error) vgdb me ... \n"); 530 VG_(gdbserver)( err->tid ); 531 VG_(umsg)("Continuing ...\n"); 532 } 533 534 /* Or maybe we want to generate the error's suppression? */ 535 if (VG_(clo_gen_suppressions) == 2 536 || (VG_(clo_gen_suppressions) == 1 537 && VG_(is_action_requested)( "Print suppression", &still_noisy )) 538 ) { 539 gen_suppression(err); 540 } 541 if (VG_(clo_gen_suppressions) == 1 && !still_noisy) 542 VG_(clo_gen_suppressions) = 0; 543 } 544 545 546 /* Prints an error. Not entirely simple because of the differences 547 between XML and text mode output. 548 549 In XML mode: 550 551 * calls the tool's pre-show method, so the tool can create any 552 preamble ahead of the message, if it wants. 553 554 * prints the opening tag, and the <unique> and <tid> fields 555 556 * prints the tool-specific parts of the message 557 558 * if suppression generation is required, a suppression 559 560 * the closing tag 561 562 In text mode: 563 564 * calls the tool's pre-show method, so the tool can create any 565 preamble ahead of the message, if it wants. 566 567 * prints the tool-specific parts of the message 568 569 * calls do_actions_on_error. This optionally does a gdbserver call 570 and optionally prints a suppression; both of these may require user input. 571 */ 572 static void pp_Error ( const Error* err, Bool allow_db_attach, Bool xml ) 573 { 574 /* If this fails, you probably specified your tool's method 575 dictionary incorrectly. */ 576 vg_assert(VG_(needs).tool_errors); 577 578 if (xml) { 579 580 /* Ensure that suppression generation is either completely 581 enabled or completely disabled; either way, we won't require 582 any user input. m_main.process_cmd_line_options should 583 ensure the asserted condition holds. */ 584 vg_assert( VG_(clo_gen_suppressions) == 0 /* disabled */ 585 || VG_(clo_gen_suppressions) == 2 /* for all errors */ ); 586 587 /* Pre-show it to the tool */ 588 VG_TDICT_CALL( tool_before_pp_Error, err ); 589 590 /* standard preamble */ 591 VG_(printf_xml)("<error>\n"); 592 VG_(printf_xml)(" <unique>0x%x</unique>\n", err->unique); 593 VG_(printf_xml)(" <tid>%u</tid>\n", err->tid); 594 ThreadState* tst = VG_(get_ThreadState)(err->tid); 595 if (tst->thread_name) { 596 VG_(printf_xml)(" <threadname>%s</threadname>\n", tst->thread_name); 597 } 598 599 /* actually print it */ 600 VG_TDICT_CALL( tool_pp_Error, err ); 601 602 if (VG_(clo_gen_suppressions) > 0) 603 gen_suppression(err); 604 605 /* postamble */ 606 VG_(printf_xml)("</error>\n"); 607 VG_(printf_xml)("\n"); 608 609 } else { 610 611 if (VG_(clo_error_markers)[0]) 612 VG_(umsg)("%s\n", VG_(clo_error_markers)[0]); 613 VG_TDICT_CALL( tool_before_pp_Error, err ); 614 615 if (VG_(tdict).tool_show_ThreadIDs_for_errors 616 && err->tid > 0 && err->tid != last_tid_printed) { 617 ThreadState* tst = VG_(get_ThreadState)(err->tid); 618 if (tst->thread_name) { 619 VG_(umsg)("Thread %u %s:\n", err->tid, tst->thread_name ); 620 } else { 621 VG_(umsg)("Thread %u:\n", err->tid ); 622 } 623 last_tid_printed = err->tid; 624 } 625 626 VG_TDICT_CALL( tool_pp_Error, err ); 627 VG_(umsg)("\n"); 628 if (VG_(clo_error_markers)[1]) 629 VG_(umsg)("%s\n", VG_(clo_error_markers)[1]); 630 631 } 632 633 do_actions_on_error(err, allow_db_attach); 634 } 635 636 637 /* Construct an error */ 638 static 639 void construct_error ( Error* err, ThreadId tid, ErrorKind ekind, Addr a, 640 const HChar* s, void* extra, ExeContext* where ) 641 { 642 /* DO NOT MAKE unique_counter NON-STATIC */ 643 static UInt unique_counter = 0; 644 645 vg_assert(tid < VG_N_THREADS); 646 647 /* Core-only parts */ 648 err->unique = unique_counter++; 649 err->next = NULL; 650 err->supp = NULL; 651 err->count = 1; 652 err->tid = tid; 653 if (NULL == where) 654 err->where = VG_(record_ExeContext)( tid, 0 ); 655 else 656 err->where = where; 657 658 /* Tool-relevant parts */ 659 err->ekind = ekind; 660 err->addr = a; 661 err->extra = extra; 662 err->string = s; 663 664 /* sanity... */ 665 vg_assert( tid < VG_N_THREADS ); 666 } 667 668 669 670 /* Top-level entry point to the error management subsystem. 671 All detected errors are notified here; this routine decides if/when the 672 user should see the error. */ 673 void VG_(maybe_record_error) ( ThreadId tid, 674 ErrorKind ekind, Addr a, 675 const HChar* s, void* extra ) 676 { 677 Error err; 678 Error* p; 679 Error* p_prev; 680 UInt extra_size; 681 VgRes exe_res = Vg_MedRes; 682 static Bool stopping_message = False; 683 static Bool slowdown_message = False; 684 685 /* After M_COLLECT_NO_ERRORS_AFTER_SHOWN different errors have 686 been found, or M_COLLECT_NO_ERRORS_AFTER_FOUND total errors 687 have been found, just refuse to collect any more. This stops 688 the burden of the error-management system becoming excessive in 689 extremely buggy programs, although it does make it pretty 690 pointless to continue the Valgrind run after this point. */ 691 if (VG_(clo_error_limit) 692 && (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN 693 || n_errs_found >= M_COLLECT_NO_ERRORS_AFTER_FOUND) 694 && !VG_(clo_xml)) { 695 if (!stopping_message) { 696 VG_(umsg)("\n"); 697 698 if (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN) { 699 VG_(umsg)( 700 "More than %d different errors detected. " 701 "I'm not reporting any more.\n", 702 M_COLLECT_NO_ERRORS_AFTER_SHOWN ); 703 } else { 704 VG_(umsg)( 705 "More than %d total errors detected. " 706 "I'm not reporting any more.\n", 707 M_COLLECT_NO_ERRORS_AFTER_FOUND ); 708 } 709 710 VG_(umsg)("Final error counts will be inaccurate. " 711 "Go fix your program!\n"); 712 VG_(umsg)("Rerun with --error-limit=no to disable " 713 "this cutoff. Note\n"); 714 VG_(umsg)("that errors may occur in your program without " 715 "prior warning from\n"); 716 VG_(umsg)("Valgrind, because errors are no longer " 717 "being displayed.\n"); 718 VG_(umsg)("\n"); 719 stopping_message = True; 720 } 721 return; 722 } 723 724 /* Ignore it if error acquisition is disabled for this thread. */ 725 { ThreadState* tst = VG_(get_ThreadState)(tid); 726 if (tst->err_disablement_level > 0) 727 return; 728 } 729 730 /* After M_COLLECT_ERRORS_SLOWLY_AFTER different errors have 731 been found, be much more conservative about collecting new 732 ones. */ 733 if (n_errs_shown >= M_COLLECT_ERRORS_SLOWLY_AFTER 734 && !VG_(clo_xml)) { 735 exe_res = Vg_LowRes; 736 if (!slowdown_message) { 737 VG_(umsg)("\n"); 738 VG_(umsg)("More than %d errors detected. Subsequent errors\n", 739 M_COLLECT_ERRORS_SLOWLY_AFTER); 740 VG_(umsg)("will still be recorded, but in less " 741 "detail than before.\n"); 742 slowdown_message = True; 743 } 744 } 745 746 /* Build ourselves the error */ 747 construct_error ( &err, tid, ekind, a, s, extra, NULL ); 748 749 /* First, see if we've got an error record matching this one. */ 750 em_errlist_searches++; 751 p = errors; 752 p_prev = NULL; 753 while (p != NULL) { 754 em_errlist_cmps++; 755 if (eq_Error(exe_res, p, &err)) { 756 /* Found it. */ 757 p->count++; 758 if (p->supp != NULL) { 759 /* Deal correctly with suppressed errors. */ 760 p->supp->count++; 761 n_errs_suppressed++; 762 } else { 763 n_errs_found++; 764 } 765 766 /* Move p to the front of the list so that future searches 767 for it are faster. It also allows to print the last 768 error (see VG_(show_last_error). */ 769 if (p_prev != NULL) { 770 vg_assert(p_prev->next == p); 771 p_prev->next = p->next; 772 p->next = errors; 773 errors = p; 774 } 775 776 return; 777 } 778 p_prev = p; 779 p = p->next; 780 } 781 782 /* Didn't see it. Copy and add. */ 783 784 /* OK, we're really going to collect it. The context is on the stack and 785 will disappear shortly, so we must copy it. First do the main 786 (non-'extra') part. 787 788 Then VG_(tdict).tool_update_extra can update the 'extra' part. This 789 is for when there are more details to fill in which take time to work 790 out but don't affect our earlier decision to include the error -- by 791 postponing those details until now, we avoid the extra work in the 792 case where we ignore the error. Ugly. 793 794 Then, if there is an 'extra' part, copy it too, using the size that 795 VG_(tdict).tool_update_extra returned. Also allow for people using 796 the void* extra field for a scalar value like an integer. 797 */ 798 799 /* copy main part */ 800 p = VG_(malloc)("errormgr.mre.1", sizeof(Error)); 801 *p = err; 802 803 /* update 'extra' */ 804 switch (ekind) { 805 //(example code, see comment on CoreSuppKind above) 806 //case ThreadErr: 807 // vg_assert(VG_(needs).core_errors); 808 // extra_size = <something> 809 // break; 810 default: 811 vg_assert(VG_(needs).tool_errors); 812 extra_size = VG_TDICT_CALL(tool_update_extra, p); 813 break; 814 } 815 816 /* copy the error string, if there is one. 817 note: if we would have many errors with big strings, using a 818 DedupPoolAlloc for these strings will avoid duplicating 819 such string in each error using it. */ 820 if (NULL != p->string) { 821 p->string = VG_(strdup)("errormgr.mre.2", p->string); 822 } 823 824 /* copy block pointed to by 'extra', if there is one */ 825 if (NULL != p->extra && 0 != extra_size) { 826 void* new_extra = VG_(malloc)("errormgr.mre.3", extra_size); 827 VG_(memcpy)(new_extra, p->extra, extra_size); 828 p->extra = new_extra; 829 } 830 831 p->next = errors; 832 p->supp = is_suppressible_error(&err); 833 errors = p; 834 if (p->supp == NULL) { 835 /* update stats */ 836 n_err_contexts++; 837 n_errs_found++; 838 n_errs_shown++; 839 /* Actually show the error; more complex than you might think. */ 840 pp_Error( p, /*allow_db_attach*/True, VG_(clo_xml) ); 841 } else { 842 n_supp_contexts++; 843 n_errs_suppressed++; 844 p->supp->count++; 845 } 846 } 847 848 /* Second top-level entry point to the error management subsystem, for 849 errors that the tool wants to report immediately, eg. because they're 850 guaranteed to only happen once. This avoids all the recording and 851 comparing stuff. But they can be suppressed; returns True if it is 852 suppressed. Bool 'print_error' dictates whether to print the error. 853 Bool 'count_error' dictates whether to count the error in n_errs_found. 854 */ 855 Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind, Addr a, const HChar* s, 856 void* extra, ExeContext* where, Bool print_error, 857 Bool allow_db_attach, Bool count_error ) 858 { 859 Error err; 860 Supp *su; 861 862 /* Ignore it if error acquisition is disabled for this thread. */ 863 ThreadState* tst = VG_(get_ThreadState)(tid); 864 if (tst->err_disablement_level > 0) 865 return False; /* ignored, not suppressed */ 866 867 /* Build ourselves the error */ 868 construct_error ( &err, tid, ekind, a, s, extra, where ); 869 870 /* Unless it's suppressed, we're going to show it. Don't need to make 871 a copy, because it's only temporary anyway. 872 873 Then update the 'extra' part with VG_(tdict).tool_update_extra), 874 because that can have an affect on whether it's suppressed. Ignore 875 the size return value of VG_(tdict).tool_update_extra, because we're 876 not copying 'extra'. Similarly, 's' is also not copied. */ 877 (void)VG_TDICT_CALL(tool_update_extra, &err); 878 879 su = is_suppressible_error(&err); 880 if (NULL == su) { 881 if (count_error) { 882 n_errs_found++; 883 n_err_contexts++; 884 } 885 886 if (print_error) { 887 /* update stats */ 888 n_errs_shown++; 889 /* Actually show the error; more complex than you might think. */ 890 pp_Error(&err, allow_db_attach, VG_(clo_xml)); 891 } 892 return False; 893 894 } else { 895 if (count_error) { 896 n_errs_suppressed++; 897 n_supp_contexts++; 898 } 899 su->count++; 900 return True; 901 } 902 } 903 904 905 /*------------------------------------------------------------*/ 906 /*--- Exported fns ---*/ 907 /*------------------------------------------------------------*/ 908 909 /* Show the used suppressions. Returns False if no suppression 910 got used. */ 911 static Bool show_used_suppressions ( void ) 912 { 913 Supp *su; 914 Bool any_supp; 915 916 if (VG_(clo_xml)) 917 VG_(printf_xml)("<suppcounts>\n"); 918 919 any_supp = False; 920 for (su = suppressions; su != NULL; su = su->next) { 921 if (su->count <= 0) 922 continue; 923 if (VG_(clo_xml)) { 924 VG_(printf_xml)( " <pair>\n" 925 " <count>%d</count>\n" 926 " <name>%pS</name>\n" 927 " </pair>\n", 928 su->count, su->sname ); 929 } else { 930 HChar *xtra = NULL; 931 Int xtra_size = 0; 932 SizeT num_written; 933 // blank line before the first shown suppression, if any 934 if (!any_supp) 935 VG_(dmsg)("\n"); 936 937 do { 938 xtra_size += 256; 939 xtra = VG_(realloc)("errormgr.sus.1", xtra, xtra_size); 940 num_written = VG_TDICT_CALL(tool_print_extra_suppression_use, 941 su, xtra, xtra_size); 942 } while (num_written == xtra_size); // resize buffer and retry 943 944 // Ensure buffer is properly terminated 945 vg_assert(xtra[num_written] == '\0'); 946 947 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions), 948 su->clo_suppressions_i); 949 VG_(dmsg)("used_suppression: %6d %s %s:%d%s%s\n", su->count, su->sname, 950 filename, 951 su->sname_lineno, 952 num_written ? " " : "", xtra); 953 VG_(free)(xtra); 954 } 955 any_supp = True; 956 } 957 958 if (VG_(clo_xml)) 959 VG_(printf_xml)("</suppcounts>\n"); 960 961 return any_supp; 962 } 963 964 /* Show all the errors that occurred, and possibly also the 965 suppressions used. */ 966 void VG_(show_all_errors) ( Int verbosity, Bool xml ) 967 { 968 Int i, n_min; 969 Error *p, *p_min; 970 Bool any_supp; 971 972 if (verbosity == 0) 973 return; 974 975 /* If we're printing XML, just show the suppressions and stop. */ 976 if (xml) { 977 (void)show_used_suppressions(); 978 return; 979 } 980 981 /* We only get here if not printing XML. */ 982 VG_(umsg)("ERROR SUMMARY: " 983 "%u errors from %u contexts (suppressed: %u from %u)\n", 984 n_errs_found, n_err_contexts, 985 n_errs_suppressed, n_supp_contexts ); 986 987 if (verbosity <= 1) 988 return; 989 990 // We do the following only at -v or above, and only in non-XML 991 // mode 992 993 /* Print the contexts in order of increasing error count. 994 Once an error is shown, we add a huge value to its count to filter it 995 out. 996 After having shown all errors, we reset count to the original value. */ 997 for (i = 0; i < n_err_contexts; i++) { 998 n_min = (1 << 30) - 1; 999 p_min = NULL; 1000 for (p = errors; p != NULL; p = p->next) { 1001 if (p->supp != NULL) continue; 1002 if (p->count < n_min) { 1003 n_min = p->count; 1004 p_min = p; 1005 } 1006 } 1007 // XXX: this isn't right. See bug 203651. 1008 if (p_min == NULL) continue; //VG_(core_panic)("show_all_errors()"); 1009 1010 VG_(umsg)("\n"); 1011 VG_(umsg)("%d errors in context %d of %u:\n", 1012 p_min->count, i+1, n_err_contexts); 1013 pp_Error( p_min, False/*allow_db_attach*/, False /* xml */ ); 1014 1015 // We're not printing XML -- we'd have exited above if so. 1016 vg_assert(! xml); 1017 1018 if ((i+1 == VG_(clo_dump_error))) { 1019 StackTrace ips = VG_(get_ExeContext_StackTrace)(p_min->where); 1020 VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to debugging*/, 1021 ips[0], /*debugging*/True, 0xFE/*verbosity*/, 1022 /*bbs_done*/0, 1023 /*allow redir?*/True); 1024 } 1025 1026 p_min->count = p_min->count + (1 << 30); 1027 } 1028 1029 /* reset the counts, otherwise a 2nd call does not show anything anymore */ 1030 for (p = errors; p != NULL; p = p->next) { 1031 if (p->count >= (1 << 30)) 1032 p->count = p->count - (1 << 30); 1033 } 1034 1035 1036 any_supp = show_used_suppressions(); 1037 1038 if (any_supp) 1039 VG_(umsg)("\n"); 1040 // reprint this, so users don't have to scroll way up to find 1041 // the first printing 1042 VG_(umsg)("ERROR SUMMARY: " 1043 "%u errors from %u contexts (suppressed: %u from %u)\n", 1044 n_errs_found, n_err_contexts, n_errs_suppressed, 1045 n_supp_contexts ); 1046 } 1047 1048 void VG_(show_last_error) ( void ) 1049 { 1050 if (n_err_contexts == 0) { 1051 VG_(umsg)("No errors yet\n"); 1052 return; 1053 } 1054 1055 pp_Error( errors, False/*allow_db_attach*/, False/*xml*/ ); 1056 } 1057 1058 1059 /* Show occurrence counts of all errors, in XML form. */ 1060 void VG_(show_error_counts_as_XML) ( void ) 1061 { 1062 Error* err; 1063 VG_(printf_xml)("<errorcounts>\n"); 1064 for (err = errors; err != NULL; err = err->next) { 1065 if (err->supp != NULL) 1066 continue; 1067 if (err->count <= 0) 1068 continue; 1069 VG_(printf_xml)(" <pair>\n"); 1070 VG_(printf_xml)(" <count>%d</count>\n", err->count); 1071 VG_(printf_xml)(" <unique>0x%x</unique>\n", err->unique); 1072 VG_(printf_xml)(" </pair>\n"); 1073 } 1074 VG_(printf_xml)("</errorcounts>\n"); 1075 VG_(printf_xml)("\n"); 1076 } 1077 1078 1079 /*------------------------------------------------------------*/ 1080 /*--- Suppression parsing ---*/ 1081 /*------------------------------------------------------------*/ 1082 1083 /* Get the next char from fd into *out_buf. Returns 1 if success, 1084 0 if eof or < 0 if error. */ 1085 1086 static Int get_char ( Int fd, HChar* out_buf ) 1087 { 1088 Int r; 1089 static HChar buf[256]; 1090 static Int buf_size = 0; 1091 static Int buf_used = 0; 1092 vg_assert(buf_size >= 0 && buf_size <= sizeof buf); 1093 vg_assert(buf_used >= 0 && buf_used <= buf_size); 1094 if (buf_used == buf_size) { 1095 r = VG_(read)(fd, buf, sizeof buf); 1096 if (r < 0) return r; /* read failed */ 1097 vg_assert(r >= 0 && r <= sizeof buf); 1098 buf_size = r; 1099 buf_used = 0; 1100 } 1101 if (buf_size == 0) 1102 return 0; /* eof */ 1103 vg_assert(buf_size >= 0 && buf_size <= sizeof buf); 1104 vg_assert(buf_used >= 0 && buf_used < buf_size); 1105 *out_buf = buf[buf_used]; 1106 buf_used++; 1107 return 1; 1108 } 1109 1110 // Get a non blank non comment line. 1111 // Returns True if eof. 1112 static Bool get_nbnc_line ( Int fd, HChar** bufpp, SizeT* nBufp, Int* lineno ) 1113 { 1114 HChar* buf = *bufpp; 1115 SizeT nBuf = *nBufp; 1116 HChar ch; 1117 Int n, i; 1118 1119 vg_assert(lineno); // lineno needed to correctly track line numbers. 1120 1121 while (True) { 1122 buf[0] = 0; 1123 /* First, read until a non-blank char appears. */ 1124 while (True) { 1125 n = get_char(fd, &ch); 1126 if (n == 1 && !VG_(isspace)(ch)) break; 1127 if (n == 1 && ch == '\n') 1128 (*lineno)++; 1129 if (n <= 0) return True; 1130 } 1131 1132 /* Now, read the line into buf. */ 1133 i = 0; 1134 buf[i++] = ch; buf[i] = 0; 1135 while (True) { 1136 n = get_char(fd, &ch); 1137 if (n <= 0) return False; /* the next call will return True */ 1138 if (ch == '\n') 1139 (*lineno)++; 1140 if (ch == '\n') break; 1141 if (i > 0 && i == nBuf-1) { 1142 *nBufp = nBuf = nBuf * 2; 1143 #define RIDICULOUS 100000 1144 vg_assert2(nBuf < RIDICULOUS, // Just a sanity check, really. 1145 "VG_(get_line): line longer than %d chars, aborting\n", 1146 RIDICULOUS); 1147 *bufpp = buf = VG_(realloc)("errormgr.get_line.1", buf, nBuf); 1148 } 1149 buf[i++] = ch; buf[i] = 0; 1150 } 1151 while (i > 1 && VG_(isspace)(buf[i-1])) { 1152 i--; buf[i] = 0; 1153 }; 1154 1155 // VG_(printf)("The line *%p %d is '%s'\n", lineno, *lineno, buf); 1156 /* Ok, we have a line. If a non-comment line, return. 1157 If a comment line, start all over again. */ 1158 if (buf[0] != '#') return False; 1159 } 1160 } 1161 1162 // True if buf starts with fun: or obj: or is ... 1163 static Bool is_location_line (const HChar* buf) 1164 { 1165 return VG_(strncmp)(buf, "fun:", 4) == 0 1166 || VG_(strncmp)(buf, "obj:", 4) == 0 1167 || VG_(strcmp)(buf, "...") == 0; 1168 } 1169 1170 Bool VG_(get_line) ( Int fd, HChar** bufpp, SizeT* nBufp, Int* lineno ) 1171 { 1172 Bool eof = get_nbnc_line (fd, bufpp, nBufp, lineno); 1173 1174 if (eof) 1175 return True; 1176 1177 if (is_location_line(*bufpp)) 1178 return True; // Not a extra suppr line 1179 else 1180 return False; // A suppression extra line 1181 } 1182 1183 /* True if s contains no wildcard (?, *) characters. */ 1184 static Bool is_simple_str (const HChar *s) 1185 { 1186 while (*s) { 1187 if (*s == '?' || *s == '*') 1188 return False; 1189 s++; 1190 } 1191 return True; 1192 } 1193 1194 /* buf contains the raw name of a caller, supposedly either 1195 fun:some_function_name or 1196 obj:some_object_name or 1197 ... 1198 Set p->ty and p->name accordingly. 1199 p->name is allocated and set to the string 1200 after the descriptor (fun: or obj:) part. 1201 Returns False if failed. 1202 */ 1203 static Bool setLocationTy ( SuppLoc* p, const HChar *buf ) 1204 { 1205 if (VG_(strncmp)(buf, "fun:", 4) == 0) { 1206 p->name = VG_(strdup)("errormgr.sLTy.1", buf+4); 1207 p->name_is_simple_str = is_simple_str (p->name); 1208 p->ty = FunName; 1209 return True; 1210 } 1211 if (VG_(strncmp)(buf, "obj:", 4) == 0) { 1212 p->name = VG_(strdup)("errormgr.sLTy.2", buf+4); 1213 p->name_is_simple_str = is_simple_str (p->name); 1214 p->ty = ObjName; 1215 return True; 1216 } 1217 if (VG_(strcmp)(buf, "...") == 0) { 1218 p->name = NULL; 1219 p->name_is_simple_str = False; 1220 p->ty = DotDotDot; 1221 return True; 1222 } 1223 VG_(printf)("location should be \"...\", or should start " 1224 "with \"fun:\" or \"obj:\"\n"); 1225 return False; 1226 } 1227 1228 1229 /* Look for "tool" in a string like "tool1,tool2,tool3" */ 1230 static Bool tool_name_present(const HChar *name, const HChar *names) 1231 { 1232 Bool found; 1233 HChar *s = NULL; /* Shut gcc up */ 1234 Int len = VG_(strlen)(name); 1235 1236 found = (NULL != (s = VG_(strstr)(names, name)) && 1237 (s == names || *(s-1) == ',') && 1238 (*(s+len) == ',' || *(s+len) == '\0') 1239 ); 1240 1241 return found; 1242 } 1243 1244 /* Read suppressions from the file specified in 1245 VG_(clo_suppressions)[clo_suppressions_i] 1246 and place them in the suppressions list. If there's any difficulty 1247 doing this, just give up -- there's no point in trying to recover. 1248 */ 1249 static void load_one_suppressions_file ( Int clo_suppressions_i ) 1250 { 1251 const HChar* filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions), 1252 clo_suppressions_i); 1253 SysRes sres; 1254 Int fd, i, j, lineno = 0; 1255 Bool got_a_location_line_read_by_tool; 1256 Bool eof; 1257 SizeT nBuf = 200; 1258 HChar* buf = VG_(malloc)("errormgr.losf.1", nBuf); 1259 HChar* tool_names; 1260 HChar* supp_name; 1261 const HChar* err_str = NULL; 1262 SuppLoc tmp_callers[VG_DEEPEST_BACKTRACE]; 1263 1264 // Check it's not a directory. 1265 if (VG_(is_dir)( filename )) { 1266 if (VG_(clo_xml)) 1267 VG_(printf_xml)("</valgrindoutput>\n"); 1268 VG_(umsg)("FATAL: suppressions file \"%s\" is a directory\n", filename ); 1269 VG_(exit)(1); 1270 } 1271 1272 // Open the suppression file. 1273 sres = VG_(open)( filename, VKI_O_RDONLY, 0 ); 1274 if (sr_isError(sres)) { 1275 if (VG_(clo_xml)) 1276 VG_(printf_xml)("</valgrindoutput>\n"); 1277 VG_(umsg)("FATAL: can't open suppressions file \"%s\"\n", filename ); 1278 VG_(exit)(1); 1279 } 1280 fd = sr_Res(sres); 1281 1282 # define BOMB(S) { err_str = S; goto syntax_error; } 1283 1284 while (True) { 1285 /* Assign and initialise the two suppression halves (core and tool) */ 1286 Supp* supp; 1287 supp = VG_(malloc)("errormgr.losf.1", sizeof(Supp)); 1288 supp->count = 0; 1289 1290 // Initialise temporary reading-in buffer. 1291 for (i = 0; i < VG_DEEPEST_BACKTRACE; i++) { 1292 tmp_callers[i].ty = NoName; 1293 tmp_callers[i].name_is_simple_str = False; 1294 tmp_callers[i].name = NULL; 1295 } 1296 1297 supp->string = supp->extra = NULL; 1298 1299 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno ); 1300 if (eof) { 1301 VG_(free)(supp); 1302 break; 1303 } 1304 1305 if (!VG_STREQ(buf, "{")) BOMB("expected '{' or end-of-file"); 1306 1307 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno ); 1308 1309 if (eof || VG_STREQ(buf, "}")) BOMB("unexpected '}'"); 1310 1311 supp->sname = VG_(strdup)("errormgr.losf.2", buf); 1312 supp->clo_suppressions_i = clo_suppressions_i; 1313 supp->sname_lineno = lineno; 1314 1315 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno ); 1316 1317 if (eof) BOMB("unexpected end-of-file (expecting tool:suppr)"); 1318 1319 /* Check it has the "tool1,tool2,...:supp" form (look for ':') */ 1320 i = 0; 1321 while (True) { 1322 if (buf[i] == ':') break; 1323 if (buf[i] == '\0') BOMB("malformed 'tool1,tool2,...:supp' line"); 1324 i++; 1325 } 1326 buf[i] = '\0'; /* Replace ':', splitting into two strings */ 1327 1328 tool_names = & buf[0]; 1329 supp_name = & buf[i+1]; 1330 1331 if (VG_(needs).core_errors && tool_name_present("core", tool_names)) 1332 { 1333 // A core suppression 1334 //(example code, see comment on CoreSuppKind above) 1335 //if (VG_STREQ(supp_name, "Thread")) 1336 // supp->skind = ThreadSupp; 1337 //else 1338 BOMB("unknown core suppression type"); 1339 } 1340 else if (VG_(needs).tool_errors && 1341 tool_name_present(VG_(details).name, tool_names)) 1342 { 1343 // A tool suppression 1344 if (VG_TDICT_CALL(tool_recognised_suppression, supp_name, supp)) { 1345 /* Do nothing, function fills in supp->skind */ 1346 } else { 1347 BOMB("unknown tool suppression type"); 1348 } 1349 } 1350 else { 1351 // Ignore rest of suppression 1352 while (True) { 1353 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno ); 1354 if (eof) BOMB("unexpected end-of-file (when skipping suppression)"); 1355 if (VG_STREQ(buf, "}")) 1356 break; 1357 } 1358 VG_(free)(supp->sname); 1359 VG_(free)(supp); 1360 continue; 1361 } 1362 1363 buf[0] = 0; 1364 // tool_read_extra_suppression_info might read lines 1365 // from fd till a location line. 1366 if (VG_(needs).tool_errors && 1367 !VG_TDICT_CALL(tool_read_extra_suppression_info, 1368 fd, &buf, &nBuf, &lineno, supp)) 1369 { 1370 BOMB("bad or missing extra suppression info"); 1371 } 1372 1373 got_a_location_line_read_by_tool = buf[0] != 0 && is_location_line(buf); 1374 1375 /* the main frame-descriptor reading loop */ 1376 i = 0; 1377 while (True) { 1378 if (got_a_location_line_read_by_tool) { 1379 got_a_location_line_read_by_tool = False; 1380 eof = False; 1381 } else { 1382 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno ); 1383 } 1384 if (eof) 1385 BOMB("unexpected end-of-file (when reading stack trace)"); 1386 if (VG_STREQ(buf, "}")) { 1387 if (i > 0) { 1388 break; 1389 } else { 1390 BOMB("missing stack trace"); 1391 } 1392 } 1393 if (i == VG_DEEPEST_BACKTRACE) 1394 BOMB("too many callers in stack trace"); 1395 if (i > 0 && i >= VG_(clo_backtrace_size)) 1396 break; 1397 if (!setLocationTy(&(tmp_callers[i]), buf)) 1398 BOMB("location should be \"...\", or should start " 1399 "with \"fun:\" or \"obj:\""); 1400 i++; 1401 } 1402 1403 // If the num callers is >= VG_(clo_backtrace_size), ignore any extra 1404 // lines and grab the '}'. 1405 if (!VG_STREQ(buf, "}")) { 1406 do { 1407 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno ); 1408 } while (!eof && !VG_STREQ(buf, "}")); 1409 } 1410 1411 // Reject entries which are entirely composed of frame 1412 // level wildcards. 1413 vg_assert(i > 0); // guaranteed by frame-descriptor reading loop 1414 for (j = 0; j < i; j++) { 1415 if (tmp_callers[j].ty == FunName || tmp_callers[j].ty == ObjName) 1416 break; 1417 vg_assert(tmp_callers[j].ty == DotDotDot); 1418 } 1419 vg_assert(j >= 0 && j <= i); 1420 if (j == i) { 1421 // we didn't find any non-"..." entries 1422 BOMB("suppression must contain at least one location " 1423 "line which is not \"...\""); 1424 } 1425 1426 // Copy tmp_callers[] into supp->callers[] 1427 supp->n_callers = i; 1428 supp->callers = VG_(malloc)("errormgr.losf.4", i * sizeof(SuppLoc)); 1429 for (i = 0; i < supp->n_callers; i++) { 1430 supp->callers[i] = tmp_callers[i]; 1431 } 1432 1433 supp->next = suppressions; 1434 suppressions = supp; 1435 } 1436 VG_(free)(buf); 1437 VG_(close)(fd); 1438 return; 1439 1440 syntax_error: 1441 if (VG_(clo_xml)) 1442 VG_(printf_xml)("</valgrindoutput>\n"); 1443 VG_(umsg)("FATAL: in suppressions file \"%s\" near line %d:\n", 1444 filename, lineno ); 1445 VG_(umsg)(" %s\n", err_str ); 1446 1447 VG_(close)(fd); 1448 VG_(umsg)("exiting now.\n"); 1449 VG_(exit)(1); 1450 1451 # undef BOMB 1452 } 1453 1454 1455 void VG_(load_suppressions) ( void ) 1456 { 1457 Int i; 1458 suppressions = NULL; 1459 for (i = 0; i < VG_(sizeXA)(VG_(clo_suppressions)); i++) { 1460 if (VG_(clo_verbosity) > 1) { 1461 VG_(dmsg)("Reading suppressions file: %s\n", 1462 *(HChar**) VG_(indexXA)(VG_(clo_suppressions), i)); 1463 } 1464 load_one_suppressions_file( i ); 1465 } 1466 } 1467 1468 1469 /*------------------------------------------------------------*/ 1470 /*--- Matching errors to suppressions ---*/ 1471 /*------------------------------------------------------------*/ 1472 1473 /* Parameterising functions for the use of VG_(generic_match) in 1474 suppression-vs-error matching. The suppression frames (SuppLoc) 1475 play the role of 'pattern'-element, and the error frames (IPs, 1476 hence simply Addrs) play the role of 'input'. In short then, we're 1477 matching a sequence of Addrs against a pattern composed of a 1478 sequence of SuppLocs. 1479 */ 1480 static Bool supploc_IsStar ( const void* supplocV ) 1481 { 1482 const SuppLoc* supploc = supplocV; 1483 return supploc->ty == DotDotDot; 1484 } 1485 1486 static Bool supploc_IsQuery ( const void* supplocV ) 1487 { 1488 return False; /* there's no '?' equivalent in the supp syntax */ 1489 } 1490 1491 /* IPtoFunOrObjCompleter is a lazy completer of the IPs 1492 needed to match an error with the suppression patterns. 1493 The matching between an IP and a suppression pattern is done either 1494 with the IP function name or with the IP object name. 1495 First time the fun or obj name is needed for an IP member 1496 of a stack trace, it will be computed and stored in names. 1497 Also, if the IP corresponds to one or more inlined function calls, 1498 the inlined function names are expanded. 1499 The IPtoFunOrObjCompleter type is designed to minimise the nr of 1500 allocations and the nr of debuginfo search. */ 1501 typedef 1502 struct { 1503 StackTrace ips; // stack trace we are lazily completing. 1504 UWord n_ips; // nr of elements in ips. 1505 1506 // VG_(generic_match) calls haveInputInpC to check 1507 // for the presence of an input element identified by ixInput 1508 // (i.e. a number that identifies the ixInput element of the 1509 // input sequence). It calls supp_pattEQinp to match this input 1510 // element with a pattern. 1511 // When inlining info is used to provide inlined function calls 1512 // in stacktraces, one IP in ips can be expanded in several 1513 // function names. So, each time input (or presence of input) 1514 // is requested by VG_(generic_match), we will expand 1515 // more IP of ips till we have expanded enough to reach the 1516 // input element requested (or we cannot expand anymore). 1517 1518 UWord n_ips_expanded; 1519 // n_ips_expanded maintains the nr of elements in ips that we have 1520 // already expanded. 1521 UWord n_expanded; 1522 // n_expanded maintains the nr of elements resulting from the expansion 1523 // of the n_ips_expanded IPs. Without inlined function calls, 1524 // n_expanded == n_ips_expanded. With inlining info, 1525 // n_expanded >= n_ips_expanded. 1526 1527 Int* n_offsets_per_ip; 1528 // n_offsets_per_ip[i] gives the nr of offsets in fun_offsets and 1529 // obj_offsets resulting of the expansion of ips[i]. 1530 // The sum of all n_expanded_per_ip must be equal to n_expanded. 1531 // This array allows to retrieve the position in ips corresponding to 1532 // an ixInput. 1533 1534 // size (in elements) of fun_offsets and obj_offsets. 1535 // (fun|obj)_offsets are reallocated if more space is needed 1536 // to expand an IP. 1537 UWord sz_offsets; 1538 1539 Int* fun_offsets; 1540 // fun_offsets[ixInput] is the offset in names where the 1541 // function name for the ixInput element of the input sequence 1542 // can be found. As one IP of ips can be expanded in several 1543 // function calls due to inlined function calls, we can have more 1544 // elements in fun_offsets than in ips. 1545 // An offset -1 means the function name has not yet been computed. 1546 Int* obj_offsets; 1547 // Similarly, obj_offsets[ixInput] gives the offset for the 1548 // object name for ips[ixInput] 1549 // (-1 meaning object name not yet been computed). 1550 1551 // All function names and object names will be concatenated 1552 // in names. names is reallocated on demand. 1553 HChar *names; 1554 Int names_szB; // size of names. 1555 Int names_free; // offset first free HChar in names. 1556 } 1557 IPtoFunOrObjCompleter; 1558 1559 static void pp_ip2fo (const IPtoFunOrObjCompleter* ip2fo) 1560 { 1561 Int i, j; 1562 Int o; 1563 1564 VG_(printf)("n_ips %lu n_ips_expanded %lu resulting in n_expanded %lu\n", 1565 ip2fo->n_ips, ip2fo->n_ips_expanded, ip2fo->n_expanded); 1566 for (i = 0; i < ip2fo->n_ips_expanded; i++) { 1567 o = 0; 1568 for (j = 0; j < i; j++) 1569 o += ip2fo->n_offsets_per_ip[j]; 1570 VG_(printf)("ips %d 0x08%lx offset [%d,%d] ", 1571 i, ip2fo->ips[i], 1572 o, o+ip2fo->n_offsets_per_ip[i]-1); 1573 for (j = 0; j < ip2fo->n_offsets_per_ip[i]; j++) { 1574 VG_(printf)("%sfun:%s obj:%s\n", 1575 j == 0 ? "" : " ", 1576 ip2fo->fun_offsets[o+j] == -1 ? 1577 "<not expanded>" : &ip2fo->names[ip2fo->fun_offsets[o+j]], 1578 ip2fo->obj_offsets[o+j] == -1 ? 1579 "<not expanded>" : &ip2fo->names[ip2fo->obj_offsets[o+j]]); 1580 } 1581 } 1582 } 1583 1584 /* free the memory in ip2fo. 1585 At debuglog 4, su (or NULL) will be used to show the matching 1586 (or non matching) with ip2fo. */ 1587 static void clearIPtoFunOrObjCompleter ( const Supp *su, 1588 IPtoFunOrObjCompleter* ip2fo) 1589 { 1590 if (DEBUG_ERRORMGR || VG_(debugLog_getLevel)() >= 4) { 1591 if (su) { 1592 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions), 1593 su->clo_suppressions_i); 1594 VG_(dmsg)("errormgr matching end suppression %s %s:%d matched:\n", 1595 su->sname, 1596 filename, 1597 su->sname_lineno); 1598 } else 1599 VG_(dmsg)("errormgr matching end no suppression matched:\n"); 1600 VG_(pp_StackTrace) (ip2fo->ips, ip2fo->n_ips); 1601 pp_ip2fo(ip2fo); 1602 } 1603 if (ip2fo->n_offsets_per_ip) VG_(free)(ip2fo->n_offsets_per_ip); 1604 if (ip2fo->fun_offsets) VG_(free)(ip2fo->fun_offsets); 1605 if (ip2fo->obj_offsets) VG_(free)(ip2fo->obj_offsets); 1606 if (ip2fo->names) VG_(free)(ip2fo->names); 1607 } 1608 1609 /* Grow ip2fo->names to ensure we have NEEDED characters available 1610 in ip2fo->names and returns a pointer to the first free char. */ 1611 static HChar* grow_names(IPtoFunOrObjCompleter* ip2fo, SizeT needed) 1612 { 1613 if (ip2fo->names_szB 1614 < ip2fo->names_free + needed) { 1615 if (needed < ERRTXT_LEN) needed = ERRTXT_LEN; 1616 1617 ip2fo->names 1618 = VG_(realloc)("foc_names", 1619 ip2fo->names, 1620 ip2fo->names_szB + needed); 1621 ip2fo->names_szB += needed; 1622 } 1623 return ip2fo->names + ip2fo->names_free; 1624 } 1625 1626 /* foComplete returns the function name or object name for ixInput. 1627 If needFun, returns the function name for this input 1628 else returns the object name for this input. 1629 The function name or object name will be computed and added in 1630 names if not yet done. */ 1631 static HChar* foComplete(IPtoFunOrObjCompleter* ip2fo, 1632 Int ixInput, Bool needFun) 1633 { 1634 vg_assert (ixInput < ip2fo->n_expanded); 1635 vg_assert (VG_(clo_read_inline_info) || ixInput < ip2fo->n_ips); 1636 1637 // ptr to the offset array for function offsets (if needFun) 1638 // or object offsets (if !needFun). 1639 Int** offsets; 1640 if (needFun) 1641 offsets = &ip2fo->fun_offsets; 1642 else 1643 offsets = &ip2fo->obj_offsets; 1644 1645 // Complete Fun name or Obj name for IP if not yet done. 1646 if ((*offsets)[ixInput] == -1) { 1647 const HChar* caller; 1648 1649 (*offsets)[ixInput] = ip2fo->names_free; 1650 if (DEBUG_ERRORMGR) VG_(printf)("marking %s ixInput %d offset %d\n", 1651 needFun ? "fun" : "obj", 1652 ixInput, ip2fo->names_free); 1653 if (needFun) { 1654 // With inline info, fn names must have been completed already. 1655 vg_assert (!VG_(clo_read_inline_info)); 1656 /* Get the function name into 'caller_name', or "???" 1657 if unknown. */ 1658 // Nb: C++-mangled names are used in suppressions. Do, though, 1659 // Z-demangle them, since otherwise it's possible to wind 1660 // up comparing "malloc" in the suppression against 1661 // "_vgrZU_libcZdsoZa_malloc" in the backtrace, and the 1662 // two of them need to be made to match. 1663 if (!VG_(get_fnname_no_cxx_demangle)(ip2fo->ips[ixInput], 1664 &caller, 1665 NULL)) 1666 caller = "???"; 1667 } else { 1668 /* Get the object name into 'caller_name', or "???" 1669 if unknown. */ 1670 UWord i; 1671 UWord last_expand_pos_ips = 0; 1672 UWord pos_ips; 1673 1674 /* First get the pos in ips corresponding to ixInput */ 1675 for (pos_ips = 0; pos_ips < ip2fo->n_expanded; pos_ips++) { 1676 last_expand_pos_ips += ip2fo->n_offsets_per_ip[pos_ips]; 1677 if (ixInput < last_expand_pos_ips) 1678 break; 1679 } 1680 /* pos_ips is the position in ips corresponding to ixInput. 1681 last_expand_pos_ips is the last offset in fun/obj where 1682 ips[pos_ips] has been expanded. */ 1683 1684 if (!VG_(get_objname)(ip2fo->ips[pos_ips], &caller)) 1685 caller = "???"; 1686 1687 // Have all inlined calls pointing at this object name 1688 for (i = last_expand_pos_ips - ip2fo->n_offsets_per_ip[pos_ips] + 1; 1689 i < last_expand_pos_ips; 1690 i++) { 1691 ip2fo->obj_offsets[i] = ip2fo->names_free; 1692 if (DEBUG_ERRORMGR) 1693 VG_(printf) (" set obj_offset %lu to %d\n", 1694 i, ip2fo->names_free); 1695 } 1696 } 1697 SizeT caller_len = VG_(strlen)(caller); 1698 HChar* caller_name = grow_names(ip2fo, caller_len + 1); 1699 VG_(strcpy)(caller_name, caller); 1700 ip2fo->names_free += caller_len + 1; 1701 if (DEBUG_ERRORMGR) pp_ip2fo(ip2fo); 1702 } 1703 1704 return ip2fo->names + (*offsets)[ixInput]; 1705 } 1706 1707 // Grow fun and obj _offsets arrays to have at least n_req elements. 1708 // Ensure n_offsets_per_ip is allocated. 1709 static void grow_offsets(IPtoFunOrObjCompleter* ip2fo, Int n_req) 1710 { 1711 Int i; 1712 1713 // n_offsets_per_ip must always have the size of the ips array 1714 if (ip2fo->n_offsets_per_ip == NULL) { 1715 ip2fo->n_offsets_per_ip = VG_(malloc)("grow_offsets", 1716 ip2fo->n_ips * sizeof(Int)); 1717 for (i = 0; i < ip2fo->n_ips; i++) 1718 ip2fo->n_offsets_per_ip[i] = 0; 1719 } 1720 1721 if (ip2fo->sz_offsets >= n_req) 1722 return; 1723 1724 // Avoid too much re-allocation by allocating at least ip2fo->n_ips 1725 // elements and at least a few more elements than the current size. 1726 if (n_req < ip2fo->n_ips) 1727 n_req = ip2fo->n_ips; 1728 if (n_req < ip2fo->sz_offsets + 5) 1729 n_req = ip2fo->sz_offsets + 5; 1730 1731 ip2fo->fun_offsets = VG_(realloc)("grow_offsets", ip2fo->fun_offsets, 1732 n_req * sizeof(Int)); 1733 for (i = ip2fo->sz_offsets; i < n_req; i++) 1734 ip2fo->fun_offsets[i] = -1; 1735 1736 ip2fo->obj_offsets = VG_(realloc)("grow_offsets", ip2fo->obj_offsets, 1737 n_req * sizeof(Int)); 1738 for (i = ip2fo->sz_offsets; i < n_req; i++) 1739 ip2fo->obj_offsets[i] = -1; 1740 1741 ip2fo->sz_offsets = n_req; 1742 } 1743 1744 // Expands more IPs from ip2fo->ips. 1745 static void expandInput (IPtoFunOrObjCompleter* ip2fo, UWord ixInput ) 1746 { 1747 while (ip2fo->n_ips_expanded < ip2fo->n_ips 1748 && ip2fo->n_expanded <= ixInput) { 1749 if (VG_(clo_read_inline_info)) { 1750 // Expand one more IP in one or more calls. 1751 const Addr IP = ip2fo->ips[ip2fo->n_ips_expanded]; 1752 InlIPCursor *iipc; 1753 1754 iipc = VG_(new_IIPC)(IP); 1755 // The only thing we really need is the nr of inlined fn calls 1756 // corresponding to the IP we will expand. 1757 // However, computing this is mostly the same as finding 1758 // the function name. So, let's directly complete the function name. 1759 do { 1760 const HChar *caller; 1761 grow_offsets(ip2fo, ip2fo->n_expanded+1); 1762 ip2fo->fun_offsets[ip2fo->n_expanded] = ip2fo->names_free; 1763 if (!VG_(get_fnname_no_cxx_demangle)(IP, 1764 &caller, 1765 iipc)) 1766 caller = "???"; 1767 SizeT caller_len = VG_(strlen)(caller); 1768 HChar* caller_name = grow_names(ip2fo, caller_len + 1); 1769 VG_(strcpy)(caller_name, caller); 1770 ip2fo->names_free += caller_len + 1; 1771 ip2fo->n_expanded++; 1772 ip2fo->n_offsets_per_ip[ip2fo->n_ips_expanded]++; 1773 } while (VG_(next_IIPC)(iipc)); 1774 ip2fo->n_ips_expanded++; 1775 VG_(delete_IIPC) (iipc); 1776 } else { 1777 // Without inlined fn call info, expansion simply 1778 // consists in allocating enough elements in (fun|obj)_offsets. 1779 // The function or object names themselves will be completed 1780 // when requested. 1781 Int i; 1782 grow_offsets(ip2fo, ip2fo->n_ips); 1783 ip2fo->n_ips_expanded = ip2fo->n_ips; 1784 ip2fo->n_expanded = ip2fo->n_ips; 1785 for (i = 0; i < ip2fo->n_ips; i++) 1786 ip2fo->n_offsets_per_ip[i] = 1; 1787 } 1788 } 1789 } 1790 1791 static Bool haveInputInpC (void* inputCompleter, UWord ixInput ) 1792 { 1793 IPtoFunOrObjCompleter* ip2fo = inputCompleter; 1794 expandInput(ip2fo, ixInput); 1795 return ixInput < ip2fo->n_expanded; 1796 } 1797 1798 static Bool supp_pattEQinp ( const void* supplocV, const void* addrV, 1799 void* inputCompleter, UWord ixInput ) 1800 { 1801 const SuppLoc* supploc = supplocV; /* PATTERN */ 1802 IPtoFunOrObjCompleter* ip2fo = inputCompleter; 1803 HChar* funobj_name; // Fun or Obj name. 1804 Bool ret; 1805 1806 expandInput(ip2fo, ixInput); 1807 vg_assert(ixInput < ip2fo->n_expanded); 1808 1809 /* So, does this IP address match this suppression-line? */ 1810 switch (supploc->ty) { 1811 case DotDotDot: 1812 /* supp_pattEQinp is a callback from VG_(generic_match). As 1813 per the spec thereof (see include/pub_tool_seqmatch.h), we 1814 should never get called with a pattern value for which the 1815 _IsStar or _IsQuery function would return True. Hence 1816 this can't happen. */ 1817 vg_assert(0); 1818 case ObjName: 1819 funobj_name = foComplete(ip2fo, ixInput, False /*needFun*/); 1820 break; 1821 case FunName: 1822 funobj_name = foComplete(ip2fo, ixInput, True /*needFun*/); 1823 break; 1824 default: 1825 vg_assert(0); 1826 } 1827 1828 /* So now we have the function or object name in funobj_name, and 1829 the pattern (at the character level) to match against is in 1830 supploc->name. Hence (and leading to a re-entrant call of 1831 VG_(generic_match) if there is a wildcard character): */ 1832 if (supploc->name_is_simple_str) 1833 ret = VG_(strcmp) (supploc->name, funobj_name) == 0; 1834 else 1835 ret = VG_(string_match)(supploc->name, funobj_name); 1836 if (DEBUG_ERRORMGR) 1837 VG_(printf) ("supp_pattEQinp %s patt %s ixUnput %lu value:%s match:%s\n", 1838 supploc->ty == FunName ? "fun" : "obj", 1839 supploc->name, ixInput, funobj_name, 1840 ret ? "yes" : "no"); 1841 return ret; 1842 } 1843 1844 ///////////////////////////////////////////////////// 1845 1846 static Bool supp_matches_callers(IPtoFunOrObjCompleter* ip2fo, 1847 const Supp* su) 1848 { 1849 /* Unwrap the args and set up the correct parameterisation of 1850 VG_(generic_match), using supploc_IsStar, supploc_IsQuery and 1851 supp_pattEQinp. */ 1852 /* note, StackTrace ip2fo->ips === Addr* */ 1853 SuppLoc* supps = su->callers; 1854 UWord n_supps = su->n_callers; 1855 UWord szbPatt = sizeof(SuppLoc); 1856 Bool matchAll = False; /* we just want to match a prefix */ 1857 if (DEBUG_ERRORMGR) { 1858 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions), 1859 su->clo_suppressions_i); 1860 VG_(dmsg)(" errormgr Checking match with %s %s:%d\n", 1861 su->sname, 1862 filename, 1863 su->sname_lineno); 1864 } 1865 return 1866 VG_(generic_match)( 1867 matchAll, 1868 /*PATT*/supps, szbPatt, n_supps, 0/*initial ixPatt*/, 1869 /*INPUT*/ 1870 NULL, 0, 0, /* input/szbInput/nInput 0, as using an inputCompleter */ 1871 0/*initial ixInput*/, 1872 supploc_IsStar, supploc_IsQuery, supp_pattEQinp, 1873 ip2fo, haveInputInpC 1874 ); 1875 } 1876 1877 ///////////////////////////////////////////////////// 1878 1879 static 1880 Bool supp_matches_error(const Supp* su, const Error* err) 1881 { 1882 switch (su->skind) { 1883 //(example code, see comment on CoreSuppKind above) 1884 //case ThreadSupp: 1885 // return (err->ekind == ThreadErr); 1886 default: 1887 if (VG_(needs).tool_errors) { 1888 return VG_TDICT_CALL(tool_error_matches_suppression, err, su); 1889 } else { 1890 VG_(printf)( 1891 "\nUnhandled suppression type: %u. VG_(needs).tool_errors\n" 1892 "probably needs to be set.\n", 1893 (UInt)err->ekind); 1894 VG_(core_panic)("unhandled suppression type"); 1895 } 1896 } 1897 } 1898 1899 ///////////////////////////////////////////////////// 1900 1901 /* Does an error context match a suppression? ie is this a suppressible 1902 error? If so, return a pointer to the Supp record, otherwise NULL. 1903 Tries to minimise the number of symbol searches since they are expensive. 1904 */ 1905 static Supp* is_suppressible_error ( const Error* err ) 1906 { 1907 Supp* su; 1908 Supp* su_prev; 1909 1910 IPtoFunOrObjCompleter ip2fo; 1911 /* Conceptually, ip2fo contains an array of function names and an array of 1912 object names, corresponding to the array of IP of err->where. 1913 These names are just computed 'on demand' (so once maximum), 1914 then stored (efficiently, avoiding too many allocs) in ip2fo to be 1915 re-usable for the matching of the same IP with the next suppression 1916 pattern. 1917 1918 VG_(generic_match) gets this 'IP to Fun or Obj name completer' as one 1919 of its arguments. It will then pass it to the function 1920 supp_pattEQinp which will then lazily complete the IP function name or 1921 object name inside ip2fo. Next time the fun or obj name for the same 1922 IP is needed (i.e. for the matching with the next suppr pattern), then 1923 the fun or obj name will not be searched again in the debug info. */ 1924 1925 /* stats gathering */ 1926 em_supplist_searches++; 1927 1928 /* Prepare the lazy input completer. */ 1929 ip2fo.ips = VG_(get_ExeContext_StackTrace)(err->where); 1930 ip2fo.n_ips = VG_(get_ExeContext_n_ips)(err->where); 1931 ip2fo.n_ips_expanded = 0; 1932 ip2fo.n_expanded = 0; 1933 ip2fo.sz_offsets = 0; 1934 ip2fo.n_offsets_per_ip = NULL; 1935 ip2fo.fun_offsets = NULL; 1936 ip2fo.obj_offsets = NULL; 1937 ip2fo.names = NULL; 1938 ip2fo.names_szB = 0; 1939 ip2fo.names_free = 0; 1940 1941 /* See if the error context matches any suppression. */ 1942 if (DEBUG_ERRORMGR || VG_(debugLog_getLevel)() >= 4) 1943 VG_(dmsg)("errormgr matching begin\n"); 1944 su_prev = NULL; 1945 for (su = suppressions; su != NULL; su = su->next) { 1946 em_supplist_cmps++; 1947 if (supp_matches_error(su, err) 1948 && supp_matches_callers(&ip2fo, su)) { 1949 /* got a match. */ 1950 /* Inform the tool that err is suppressed by su. */ 1951 (void)VG_TDICT_CALL(tool_update_extra_suppression_use, err, su); 1952 /* Move this entry to the head of the list 1953 in the hope of making future searches cheaper. */ 1954 if (su_prev) { 1955 vg_assert(su_prev->next == su); 1956 su_prev->next = su->next; 1957 su->next = suppressions; 1958 suppressions = su; 1959 } 1960 clearIPtoFunOrObjCompleter(su, &ip2fo); 1961 return su; 1962 } 1963 su_prev = su; 1964 } 1965 clearIPtoFunOrObjCompleter(NULL, &ip2fo); 1966 return NULL; /* no matches */ 1967 } 1968 1969 /* Show accumulated error-list and suppression-list search stats. 1970 */ 1971 void VG_(print_errormgr_stats) ( void ) 1972 { 1973 VG_(dmsg)( 1974 " errormgr: %'lu supplist searches, %'lu comparisons during search\n", 1975 em_supplist_searches, em_supplist_cmps 1976 ); 1977 VG_(dmsg)( 1978 " errormgr: %'lu errlist searches, %'lu comparisons during search\n", 1979 em_errlist_searches, em_errlist_cmps 1980 ); 1981 } 1982 1983 /*--------------------------------------------------------------------*/ 1984 /*--- end ---*/ 1985 /*--------------------------------------------------------------------*/ 1986