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