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