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