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