2 /*--------------------------------------------------------------------*/
3 /*--- Management of error messages. m_errormgr.c ---*/
4 /*--------------------------------------------------------------------*/
7 This file is part of Valgrind, a dynamic binary instrumentation
10 Copyright (C) 2000-2010 Julian Seward
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.
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.
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
28 The GNU General Public License is contained in the file COPYING.
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
53 /*------------------------------------------------------------*/
55 /*------------------------------------------------------------*/
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
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
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
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;
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;
79 /* Running count of unsuppressed errors detected. */
80 static UInt n_errs_found = 0;
82 /* Running count of suppressed errors detected. */
83 static UInt n_errs_suppressed = 0;
85 /* Running count of unsuppressed error contexts. */
86 static UInt n_err_contexts = 0;
88 /* Running count of suppressed error contexts. */
89 static UInt n_supp_contexts = 0;
93 static Supp* is_suppressible_error ( Error* err );
95 static ThreadId last_tid_printed = 1;
97 /* Stats: number of searches of the error list initiated. */
98 static UWord em_errlist_searches = 0;
100 /* Stats: number of comparisons done during error list
102 static UWord em_errlist_cmps = 0;
104 /* Stats: number of searches of the suppression list initiated. */
105 static UWord em_supplist_searches = 0;
107 /* Stats: number of comparisons done during suppression list
109 static UWord em_supplist_cmps = 0;
111 /*------------------------------------------------------------*/
112 /*--- Error type ---*/
113 /*------------------------------------------------------------*/
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.
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.
126 // Unique tag. This gives the error a unique identity (handle) by
127 // which it can be referred to afterwords. Currently only used for
130 // NULL if unsuppressed; or ptr to suppression record.
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
144 ExeContext* VG_(get_error_where) ( Error* err )
149 ErrorKind VG_(get_error_kind) ( Error* err )
154 Addr VG_(get_error_address) ( Error* err )
159 Char* VG_(get_error_string) ( Error* err )
164 void* VG_(get_error_extra) ( Error* err )
169 UInt VG_(get_n_errs_found)( void )
174 /*------------------------------------------------------------*/
175 /*--- Suppression type ---*/
176 /*------------------------------------------------------------*/
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. */
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 */
189 /* Max number of callers for context in a suppression. */
190 #define VG_MAX_SUPP_CALLERS 24
192 /* For each caller specified for a suppression, record the nature of
193 the caller name. Not of interest to tools. */
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 */
206 Char* name; /* NULL for NoName and DotDotDot */
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'. */
216 Int count; // The number of times this error has been suppressed.
217 Char* sname; // The name by which the suppression is referred to.
219 // Length of 'callers'
221 // Array of callers, for matching stack traces. First one (name of fn
222 // where err occurs) is mandatory; rest are optional.
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.
231 SuppKind VG_(get_supp_kind) ( Supp* su )
236 Char* VG_(get_supp_string) ( Supp* su )
241 void* VG_(get_supp_extra) ( Supp* su )
247 void VG_(set_supp_kind) ( Supp* su, SuppKind skind )
252 void VG_(set_supp_string) ( Supp* su, Char* string )
257 void VG_(set_supp_extra) ( Supp* su, void* extra )
263 /*------------------------------------------------------------*/
264 /*--- Helper fns ---*/
265 /*------------------------------------------------------------*/
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)
271 return VG_(needs).core_errors && VG_(clo_verbosity) >= 1 && !VG_(clo_xml);
274 /* Compare errors, to detect duplicates.
276 static Bool eq_Error ( VgRes res, Error* e1, Error* e2 )
278 if (e1->ekind != e2->ekind)
280 if (!VG_(eq_ExeContext)(res, e1->where, e2->where))
284 //(example code, see comment on CoreSuppKind above)
286 // vg_assert(VG_(needs).core_errors);
287 // return <something>
289 if (VG_(needs).tool_errors) {
290 return VG_TDICT_CALL(tool_eq_Error, res, e1, e2);
292 VG_(printf)("\nUnhandled error type: %u. VG_(needs).tool_errors\n"
293 "probably needs to be set.\n",
295 VG_(tool_panic)("unhandled error type");
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
306 #define ERRTXT_LEN 4096
308 static void printSuppForIp_XML(UInt n, Addr ip, void* uu_opaque)
310 static UChar buf[ERRTXT_LEN];
311 if ( VG_(get_fnname_no_cxx_demangle) (ip, buf, ERRTXT_LEN) ) {
312 VG_(printf_xml_no_f_c)(" <sframe> <fun>%t</fun> </sframe>\n", buf);
314 if ( VG_(get_objname)(ip, buf, ERRTXT_LEN) ) {
315 VG_(printf_xml_no_f_c)(" <sframe> <obj>%t</obj> </sframe>\n", buf);
317 VG_(printf_xml_no_f_c)(" <sframe> <obj>*</obj> </sframe>\n");
321 static void printSuppForIp_nonXML(UInt n, Addr ip, void* textV)
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);
328 if ( VG_(get_objname)(ip, buf, ERRTXT_LEN) ) {
329 VG_(xaprintf)(text, " obj:%s\n", buf);
331 VG_(xaprintf)(text, " obj:*\n");
335 /* Generate a suppression for an error, either in text or XML mode.
337 static void gen_suppression(Error* err)
339 Char xtra[256]; /* assumed big enough (is overrun-safe) */
343 XArray* /* HChar */ text;
345 const HChar* dummy_name = "insert_a_suppression_name_here";
349 /* In XML mode, we also need to print the plain text version of the
350 suppresion in a CDATA section. What that really means is, we
351 need to generate the plaintext version both in XML and text
352 mode. So generate it into TEXT. */
353 text = VG_(newXA)( VG_(malloc), "errormgr.gen_suppression.1",
354 VG_(free), sizeof(HChar) );
357 ec = VG_(get_error_where)(err);
360 name = VG_TDICT_CALL(tool_get_error_name, err);
362 VG_(umsg)("(%s does not allow error to be suppressed)\n",
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);
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);
378 VG_(xaprintf)(text, " %s\n", xtra);
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,
387 VG_(get_ExeContext_StackTrace)(ec),
390 VG_(xaprintf)(text, "}\n");
392 VG_(xaprintf)(text, "%c", (HChar)0 );
393 // VG_(printf) of text
395 /* And now display it. */
396 if (! VG_(clo_xml) ) {
399 VG_(printf)("%s", (HChar*) VG_(indexXA)(text, 0) );
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
406 VG_(printf_xml)(" <suppression>\n");
407 VG_(printf_xml)(" <sname>%s</sname>\n", dummy_name);
408 VG_(printf_xml_no_f_c)(
409 " <skind>%t:%t</skind>\n", VG_(details).name, name);
411 VG_(printf_xml_no_f_c)(" <skaux>%t</skaux>\n", xtra);
413 // Print stack trace elements
414 VG_(apply_StackTrace)(printSuppForIp_XML,
416 VG_(get_ExeContext_StackTrace)(ec),
417 VG_(get_ExeContext_n_ips)(ec));
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");
435 /* Figure out if we want to perform a given action for this error,
436 possibly by asking the user.
438 Bool VG_(is_action_requested) ( Char* action, Bool* clo )
443 /* First off, we shouldn't be asking the user anything if
444 we're in XML mode. */
446 return False; /* That's a Nein, oder Nay as they say down here in B-W */
456 "---- %s ? --- [Return/N/n/Y/y/C/c] ---- ",
457 VG_(getpid)(), action
460 res = VG_(read)(VG_(clo_input_fd), &ch, 1);
461 if (res != 1) goto ioerror;
463 if (ch == '\n') return False;
464 if (ch != 'N' && ch != 'n' && ch != 'Y' && ch != 'y'
465 && ch != 'C' && ch != 'c') goto again;
467 res = VG_(read)(VG_(clo_input_fd), &ch2, 1);
468 if (res != 1) goto ioerror;
469 if (ch2 != '\n') goto again;
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');
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!
491 void do_actions_on_error(Error* err, Bool allow_db_attach)
493 Bool still_noisy = True;
495 /* Should be assured by caller */
496 vg_assert( ! VG_(clo_xml) );
498 /* if user wants to debug from a certain error nr, then wait for gdb/vgdb */
499 if (VG_(clo_vgdb) != Vg_VgdbNo
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");
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) ))
513 if (0) VG_(printf)("starting debugger\n");
514 VG_(start_debugger)( err->tid );
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 ))
521 gen_suppression(err);
523 if (VG_(clo_gen_suppressions) == 1 && !still_noisy)
524 VG_(clo_gen_suppressions) = 0;
528 /* Prints an error. Not entirely simple because of the differences
529 between XML and text mode output.
533 * calls the tool's pre-show method, so the tool can create any
534 preamble ahead of the message, if it wants.
536 * prints the opening tag, and the <unique> and <tid> fields
538 * prints the tool-specific parts of the message
540 * if suppression generation is required, a suppression
546 * calls the tool's pre-show method, so the tool can create any
547 preamble ahead of the message, if it wants.
549 * prints the tool-specific parts of the message
551 * calls do_actions_on_error. This optionally does a debugger
552 attach (and detach), and optionally prints a suppression; both
553 of these may require user input.
555 static void pp_Error ( Error* err, Bool allow_db_attach, Bool xml )
557 /* If this fails, you probably specified your tool's method
558 dictionary incorrectly. */
559 vg_assert(VG_(needs).tool_errors);
563 /* Note, allow_db_attach is ignored in here. */
565 /* Ensure that suppression generation is either completely
566 enabled or completely disabled; either way, we won't require
567 any user input. m_main.process_cmd_line_options should
568 ensure the asserted condition holds. */
569 vg_assert( VG_(clo_gen_suppressions) == 0 /* disabled */
570 || VG_(clo_gen_suppressions) == 2 /* for all errors */ );
572 /* Pre-show it to the tool */
573 VG_TDICT_CALL( tool_before_pp_Error, err );
575 /* standard preamble */
576 VG_(printf_xml)("<error>\n");
577 VG_(printf_xml)(" <unique>0x%x</unique>\n", err->unique);
578 VG_(printf_xml)(" <tid>%d</tid>\n", err->tid);
580 /* actually print it */
581 VG_TDICT_CALL( tool_pp_Error, err );
583 if (VG_(clo_gen_suppressions) > 0)
584 gen_suppression(err);
587 VG_(printf_xml)("</error>\n");
588 VG_(printf_xml)("\n");
592 VG_TDICT_CALL( tool_before_pp_Error, err );
594 if (VG_(tdict).tool_show_ThreadIDs_for_errors
595 && err->tid > 0 && err->tid != last_tid_printed) {
596 VG_(umsg)("Thread %d:\n", err->tid );
597 last_tid_printed = err->tid;
600 VG_TDICT_CALL( tool_pp_Error, err );
603 do_actions_on_error(err, allow_db_attach);
608 /* Construct an error */
610 void construct_error ( Error* err, ThreadId tid, ErrorKind ekind, Addr a,
611 Char* s, void* extra, ExeContext* where )
613 /* DO NOT MAKE unique_counter NON-STATIC */
614 static UInt unique_counter = 0;
616 tl_assert(tid < VG_N_THREADS);
618 /* Core-only parts */
619 err->unique = unique_counter++;
625 err->where = VG_(record_ExeContext)( tid, 0 );
629 /* Tool-relevant parts */
636 vg_assert( tid < VG_N_THREADS );
641 static Int n_errs_shown = 0;
643 /* Top-level entry point to the error management subsystem.
644 All detected errors are notified here; this routine decides if/when the
645 user should see the error. */
646 void VG_(maybe_record_error) ( ThreadId tid,
647 ErrorKind ekind, Addr a, Char* s, void* extra )
653 VgRes exe_res = Vg_MedRes;
654 static Bool stopping_message = False;
655 static Bool slowdown_message = False;
657 /* After M_COLLECT_NO_ERRORS_AFTER_SHOWN different errors have
658 been found, or M_COLLECT_NO_ERRORS_AFTER_FOUND total errors
659 have been found, just refuse to collect any more. This stops
660 the burden of the error-management system becoming excessive in
661 extremely buggy programs, although it does make it pretty
662 pointless to continue the Valgrind run after this point. */
663 if (VG_(clo_error_limit)
664 && (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN
665 || n_errs_found >= M_COLLECT_NO_ERRORS_AFTER_FOUND)
667 if (!stopping_message) {
670 if (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN) {
672 "More than %d different errors detected. "
673 "I'm not reporting any more.\n",
674 M_COLLECT_NO_ERRORS_AFTER_SHOWN );
677 "More than %d total errors detected. "
678 "I'm not reporting any more.\n",
679 M_COLLECT_NO_ERRORS_AFTER_FOUND );
682 VG_(umsg)("Final error counts will be inaccurate. "
683 "Go fix your program!\n");
684 VG_(umsg)("Rerun with --error-limit=no to disable "
685 "this cutoff. Note\n");
686 VG_(umsg)("that errors may occur in your program without "
687 "prior warning from\n");
688 VG_(umsg)("Valgrind, because errors are no longer "
689 "being displayed.\n");
691 stopping_message = True;
696 /* After M_COLLECT_ERRORS_SLOWLY_AFTER different errors have
697 been found, be much more conservative about collecting new
699 if (n_errs_shown >= M_COLLECT_ERRORS_SLOWLY_AFTER
702 if (!slowdown_message) {
704 VG_(umsg)("More than %d errors detected. Subsequent errors\n",
705 M_COLLECT_ERRORS_SLOWLY_AFTER);
706 VG_(umsg)("will still be recorded, but in less "
707 "detail than before.\n");
708 slowdown_message = True;
712 /* Build ourselves the error */
713 construct_error ( &err, tid, ekind, a, s, extra, NULL );
715 /* First, see if we've got an error record matching this one. */
716 em_errlist_searches++;
721 if (eq_Error(exe_res, p, &err)) {
724 if (p->supp != NULL) {
725 /* Deal correctly with suppressed errors. */
732 /* Move p to the front of the list so that future searches
733 for it are faster. It also allows to print the last
734 error (see VG_(show_last_error). */
735 if (p_prev != NULL) {
736 vg_assert(p_prev->next == p);
737 p_prev->next = p->next;
748 /* Didn't see it. Copy and add. */
750 /* OK, we're really going to collect it. The context is on the stack and
751 will disappear shortly, so we must copy it. First do the main
754 Then VG_(tdict).tool_update_extra can update the 'extra' part. This
755 is for when there are more details to fill in which take time to work
756 out but don't affect our earlier decision to include the error -- by
757 postponing those details until now, we avoid the extra work in the
758 case where we ignore the error. Ugly.
760 Then, if there is an 'extra' part, copy it too, using the size that
761 VG_(tdict).tool_update_extra returned. Also allow for people using
762 the void* extra field for a scalar value like an integer.
766 p = VG_(arena_malloc)(VG_AR_ERRORS, "errormgr.mre.1", sizeof(Error));
771 //(example code, see comment on CoreSuppKind above)
773 // vg_assert(VG_(needs).core_errors);
774 // extra_size = <something>
777 vg_assert(VG_(needs).tool_errors);
778 extra_size = VG_TDICT_CALL(tool_update_extra, p);
782 /* copy block pointed to by 'extra', if there is one */
783 if (NULL != p->extra && 0 != extra_size) {
784 void* new_extra = VG_(malloc)("errormgr.mre.2", extra_size);
785 VG_(memcpy)(new_extra, p->extra, extra_size);
786 p->extra = new_extra;
790 p->supp = is_suppressible_error(&err);
792 if (p->supp == NULL) {
795 /* Actually show the error; more complex than you might think. */
796 pp_Error( p, /*allow_db_attach*/True, VG_(clo_xml) );
806 /* Second top-level entry point to the error management subsystem, for
807 errors that the tool wants to report immediately, eg. because they're
808 guaranteed to only happen once. This avoids all the recording and
809 comparing stuff. But they can be suppressed; returns True if it is
810 suppressed. Bool 'print_error' dictates whether to print the error.
811 Bool 'count_error' dictates whether to count the error in n_errs_found.
813 Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind, Addr a, Char* s,
814 void* extra, ExeContext* where, Bool print_error,
815 Bool allow_db_attach, Bool count_error )
820 /* Build ourselves the error */
821 construct_error ( &err, tid, ekind, a, s, extra, where );
823 /* Unless it's suppressed, we're going to show it. Don't need to make
824 a copy, because it's only temporary anyway.
826 Then update the 'extra' part with VG_(tdict).tool_update_extra),
827 because that can have an affect on whether it's suppressed. Ignore
828 the size return value of VG_(tdict).tool_update_extra, because we're
829 not copying 'extra'. */
830 (void)VG_TDICT_CALL(tool_update_extra, &err);
832 su = is_suppressible_error(&err);
840 /* Actually show the error; more complex than you might think. */
841 pp_Error(&err, allow_db_attach, VG_(clo_xml));
858 /*------------------------------------------------------------*/
859 /*--- Exported fns ---*/
860 /*------------------------------------------------------------*/
862 /* Show the used suppressions. Returns False if no suppression
864 static Bool show_used_suppressions ( void )
870 VG_(printf_xml)("<suppcounts>\n");
873 for (su = suppressions; su != NULL; su = su->next) {
877 VG_(printf_xml_no_f_c)( " <pair>\n"
878 " <count>%d</count>\n"
881 su->count, su->sname );
883 // blank line before the first shown suppression, if any
886 VG_(dmsg)("used_suppression: %6d %s\n", su->count, su->sname);
892 VG_(printf_xml)("</suppcounts>\n");
897 /* Show all the errors that occurred, and possibly also the
898 suppressions used. */
899 void VG_(show_all_errors) ( Int verbosity, Bool xml )
908 /* If we're printing XML, just show the suppressions and stop. */
910 (void)show_used_suppressions();
914 /* We only get here if not printing XML. */
915 VG_(umsg)("ERROR SUMMARY: "
916 "%d errors from %d contexts (suppressed: %d from %d)\n",
917 n_errs_found, n_err_contexts,
918 n_errs_suppressed, n_supp_contexts );
923 // We do the following only at -v or above, and only in non-XML
926 /* Print the contexts in order of increasing error count.
927 Once an error is shown, we add a huge value to its count to filter it
928 out. After having shown all errors, we reset count to the original value. */
929 for (i = 0; i < n_err_contexts; i++) {
930 n_min = (1 << 30) - 1;
932 for (p = errors; p != NULL; p = p->next) {
933 if (p->supp != NULL) continue;
934 if (p->count < n_min) {
939 // XXX: this isn't right. See bug 203651.
940 if (p_min == NULL) continue; //VG_(tool_panic)("show_all_errors()");
943 VG_(umsg)("%d errors in context %d of %d:\n",
944 p_min->count, i+1, n_err_contexts);
945 pp_Error( p_min, False/*allow_db_attach*/, False /* xml */ );
947 // We're not printing XML -- we'd have exited above if so.
950 if ((i+1 == VG_(clo_dump_error))) {
951 StackTrace ips = VG_(get_ExeContext_StackTrace)(p_min->where);
952 VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to debugging*/,
953 ips[0], /*debugging*/True, 0xFE/*verbosity*/,
955 /*allow redir?*/True);
958 p_min->count = p_min->count + (1 << 30);
961 /* reset the counts, otherwise a 2nd call does not show anything anymore */
962 for (p = errors; p != NULL; p = p->next) {
963 if (p->count >= (1 << 30))
964 p->count = p->count - (1 << 30);
968 any_supp = show_used_suppressions();
972 // reprint this, so users don't have to scroll way up to find
973 // the first printing
974 VG_(umsg)("ERROR SUMMARY: "
975 "%d errors from %d contexts (suppressed: %d from %d)\n",
976 n_errs_found, n_err_contexts, n_errs_suppressed,
980 void VG_(show_last_error) ( void )
982 if (n_err_contexts == 0) {
983 VG_(umsg)("No errors yet\n");
987 pp_Error( errors, False/*allow_db_attach*/, False/*xml*/ );
991 /* Show occurrence counts of all errors, in XML form. */
992 void VG_(show_error_counts_as_XML) ( void )
995 VG_(printf_xml)("<errorcounts>\n");
996 for (err = errors; err != NULL; err = err->next) {
997 if (err->supp != NULL)
1001 VG_(printf_xml)(" <pair>\n");
1002 VG_(printf_xml)(" <count>%d</count>\n", err->count);
1003 VG_(printf_xml)(" <unique>0x%x</unique>\n", err->unique);
1004 VG_(printf_xml)(" </pair>\n");
1006 VG_(printf_xml)("</errorcounts>\n");
1007 VG_(printf_xml)("\n");
1011 /*------------------------------------------------------------*/
1012 /*--- Suppression parsing ---*/
1013 /*------------------------------------------------------------*/
1015 /* Get the next char from fd into *out_buf. Returns 1 if success,
1016 0 if eof or < 0 if error. */
1018 static Int get_char ( Int fd, Char* out_buf )
1021 static Char buf[256];
1022 static Int buf_size = 0;
1023 static Int buf_used = 0;
1024 vg_assert(buf_size >= 0 && buf_size <= 256);
1025 vg_assert(buf_used >= 0 && buf_used <= buf_size);
1026 if (buf_used == buf_size) {
1027 r = VG_(read)(fd, buf, 256);
1028 if (r < 0) return r; /* read failed */
1029 vg_assert(r >= 0 && r <= 256);
1035 vg_assert(buf_size >= 0 && buf_size <= 256);
1036 vg_assert(buf_used >= 0 && buf_used < buf_size);
1037 *out_buf = buf[buf_used];
1042 Bool VG_(get_line) ( Int fd, Char** bufpp, SizeT* nBufp, Int* lineno )
1045 SizeT nBuf = *nBufp;
1049 /* First, read until a non-blank char appears. */
1051 n = get_char(fd, &ch);
1052 if (n == 1 && !VG_(isspace)(ch)) break;
1053 if (n == 1 && ch == '\n' && lineno)
1055 if (n <= 0) return True;
1058 /* Now, read the line into buf. */
1060 buf[i++] = ch; buf[i] = 0;
1062 n = get_char(fd, &ch);
1063 if (n <= 0) return False; /* the next call will return True */
1064 if (ch == '\n' && lineno)
1066 if (ch == '\n') break;
1067 if (i > 0 && i == nBuf-1) {
1068 *nBufp = nBuf = nBuf * 2;
1069 #define RIDICULOUS 100000
1070 vg_assert2(nBuf < RIDICULOUS, // Just a sanity check, really.
1071 "VG_(get_line): line longer than %d chars, aborting\n",
1073 *bufpp = buf = VG_(realloc)("errormgr.get_line.1", buf, nBuf);
1075 buf[i++] = ch; buf[i] = 0;
1077 while (i > 1 && VG_(isspace)(buf[i-1])) {
1081 /* VG_(printf)("The line is '%s'\n", buf); */
1082 /* Ok, we have a line. If a non-comment line, return.
1083 If a comment line, start all over again. */
1084 if (buf[0] != '#') return False;
1089 /* *p_caller contains the raw name of a caller, supposedly either
1090 fun:some_function_name or
1091 obj:some_object_name.
1092 Set *p_ty accordingly and advance *p_caller over the descriptor
1093 (fun: or obj:) part.
1094 Returns False if failed.
1096 static Bool setLocationTy ( SuppLoc* p )
1098 if (VG_(strncmp)(p->name, "fun:", 4) == 0) {
1103 if (VG_(strncmp)(p->name, "obj:", 4) == 0) {
1108 if (VG_(strcmp)(p->name, "...") == 0) {
1113 VG_(printf)("location should be \"...\", or should start "
1114 "with \"fun:\" or \"obj:\"\n");
1119 /* Look for "tool" in a string like "tool1,tool2,tool3" */
1120 static Bool tool_name_present(Char *name, Char *names)
1123 Char *s = NULL; /* Shut gcc up */
1124 Int len = VG_(strlen)(name);
1126 found = (NULL != (s = VG_(strstr)(names, name)) &&
1127 (s == names || *(s-1) == ',') &&
1128 (*(s+len) == ',' || *(s+len) == '\0')
1134 /* Read suppressions from the file specified in VG_(clo_suppressions)
1135 and place them in the suppressions list. If there's any difficulty
1136 doing this, just give up -- there's no point in trying to recover.
1138 static void load_one_suppressions_file ( Char* filename )
1141 Int fd, i, j, lineno = 0;
1144 Char* buf = VG_(malloc)("errormgr.losf.1", nBuf);
1147 Char* err_str = NULL;
1148 SuppLoc tmp_callers[VG_MAX_SUPP_CALLERS];
1150 // Check it's not a directory.
1151 if (VG_(is_dir)( filename )) {
1153 VG_(printf_xml)("</valgrindoutput>\n");
1154 VG_(umsg)("FATAL: suppressions file \"%s\" is a directory\n", filename );
1158 // Open the suppression file.
1159 sres = VG_(open)( filename, VKI_O_RDONLY, 0 );
1160 if (sr_isError(sres)) {
1162 VG_(printf_xml)("</valgrindoutput>\n");
1163 VG_(umsg)("FATAL: can't open suppressions file \"%s\"\n", filename );
1168 # define BOMB(S) { err_str = S; goto syntax_error; }
1171 /* Assign and initialise the two suppression halves (core and tool) */
1173 supp = VG_(arena_malloc)(VG_AR_CORE, "errormgr.losf.1",
1177 // Initialise temporary reading-in buffer.
1178 for (i = 0; i < VG_MAX_SUPP_CALLERS; i++) {
1179 tmp_callers[i].ty = NoName;
1180 tmp_callers[i].name = NULL;
1183 supp->string = supp->extra = NULL;
1185 eof = VG_(get_line) ( fd, &buf, &nBuf, &lineno );
1188 if (!VG_STREQ(buf, "{")) BOMB("expected '{' or end-of-file");
1190 eof = VG_(get_line) ( fd, &buf, &nBuf, &lineno );
1192 if (eof || VG_STREQ(buf, "}")) BOMB("unexpected '}'");
1194 supp->sname = VG_(arena_strdup)(VG_AR_CORE, "errormgr.losf.2", buf);
1196 eof = VG_(get_line) ( fd, &buf, &nBuf, &lineno );
1198 if (eof) BOMB("unexpected end-of-file");
1200 /* Check it has the "tool1,tool2,...:supp" form (look for ':') */
1203 if (buf[i] == ':') break;
1204 if (buf[i] == '\0') BOMB("malformed 'tool1,tool2,...:supp' line");
1207 buf[i] = '\0'; /* Replace ':', splitting into two strings */
1209 tool_names = & buf[0];
1210 supp_name = & buf[i+1];
1212 if (VG_(needs).core_errors && tool_name_present("core", tool_names))
1214 // A core suppression
1215 //(example code, see comment on CoreSuppKind above)
1216 //if (VG_STREQ(supp_name, "Thread"))
1217 // supp->skind = ThreadSupp;
1219 BOMB("unknown core suppression type");
1221 else if (VG_(needs).tool_errors &&
1222 tool_name_present(VG_(details).name, tool_names))
1224 // A tool suppression
1225 if (VG_TDICT_CALL(tool_recognised_suppression, supp_name, supp)) {
1226 /* Do nothing, function fills in supp->skind */
1228 BOMB("unknown tool suppression type");
1232 // Ignore rest of suppression
1234 eof = VG_(get_line) ( fd, &buf, &nBuf, &lineno );
1235 if (eof) BOMB("unexpected end-of-file");
1236 if (VG_STREQ(buf, "}"))
1242 if (VG_(needs).tool_errors &&
1243 !VG_TDICT_CALL(tool_read_extra_suppression_info,
1244 fd, &buf, &nBuf, supp))
1246 BOMB("bad or missing extra suppression info");
1249 /* the main frame-descriptor reading loop */
1252 eof = VG_(get_line) ( fd, &buf, &nBuf, &lineno );
1254 BOMB("unexpected end-of-file");
1255 if (VG_STREQ(buf, "}")) {
1259 BOMB("missing stack trace");
1262 if (i == VG_MAX_SUPP_CALLERS)
1263 BOMB("too many callers in stack trace");
1264 if (i > 0 && i >= VG_(clo_backtrace_size))
1266 tmp_callers[i].name = VG_(arena_strdup)(VG_AR_CORE,
1267 "errormgr.losf.3", buf);
1268 if (!setLocationTy(&(tmp_callers[i])))
1269 BOMB("location should be \"...\", or should start "
1270 "with \"fun:\" or \"obj:\"");
1274 // If the num callers is >= VG_(clo_backtrace_size), ignore any extra
1275 // lines and grab the '}'.
1276 if (!VG_STREQ(buf, "}")) {
1278 eof = VG_(get_line) ( fd, &buf, &nBuf, &lineno );
1279 } while (!eof && !VG_STREQ(buf, "}"));
1282 // Reject entries which are entirely composed of frame
1284 vg_assert(i > 0); // guaranteed by frame-descriptor reading loop
1285 for (j = 0; j < i; j++) {
1286 if (tmp_callers[j].ty == FunName || tmp_callers[j].ty == ObjName)
1288 vg_assert(tmp_callers[j].ty == DotDotDot);
1290 vg_assert(j >= 0 && j <= i);
1292 // we didn't find any non-"..." entries
1293 BOMB("suppression must contain at least one location "
1294 "line which is not \"...\"");
1297 // Copy tmp_callers[] into supp->callers[]
1298 supp->n_callers = i;
1299 supp->callers = VG_(arena_malloc)(VG_AR_CORE, "errormgr.losf.4",
1301 for (i = 0; i < supp->n_callers; i++) {
1302 supp->callers[i] = tmp_callers[i];
1305 supp->next = suppressions;
1306 suppressions = supp;
1314 VG_(printf_xml)("</valgrindoutput>\n");
1315 VG_(umsg)("FATAL: in suppressions file \"%s\" near line %d:\n",
1317 VG_(umsg)(" %s\n", err_str );
1320 VG_(umsg)("exiting now.\n");
1327 void VG_(load_suppressions) ( void )
1330 suppressions = NULL;
1331 for (i = 0; i < VG_(clo_n_suppressions); i++) {
1332 if (VG_(clo_verbosity) > 1) {
1333 VG_(dmsg)("Reading suppressions file: %s\n",
1334 VG_(clo_suppressions)[i] );
1336 load_one_suppressions_file( VG_(clo_suppressions)[i] );
1341 /*------------------------------------------------------------*/
1342 /*--- Matching errors to suppressions ---*/
1343 /*------------------------------------------------------------*/
1345 /* Parameterising functions for the use of VG_(generic_match) in
1346 suppression-vs-error matching. The suppression frames (SuppLoc)
1347 play the role of 'pattern'-element, and the error frames (IPs,
1348 hence simply Addrs) play the role of 'input'. In short then, we're
1349 matching a sequence of Addrs against a pattern composed of a
1350 sequence of SuppLocs.
1352 static Bool supploc_IsStar ( void* supplocV )
1354 SuppLoc* supploc = (SuppLoc*)supplocV;
1355 return supploc->ty == DotDotDot;
1358 static Bool supploc_IsQuery ( void* supplocV )
1360 return False; /* there's no '?' equivalent in the supp syntax */
1363 static Bool supp_pattEQinp ( void* supplocV, void* addrV )
1365 SuppLoc* supploc = (SuppLoc*)supplocV; /* PATTERN */
1366 Addr ip = *(Addr*)addrV; /* INPUT */
1368 Char caller_name[ERRTXT_LEN];
1371 /* So, does this IP address match this suppression-line? */
1372 switch (supploc->ty) {
1374 /* supp_pattEQinp is a callback from VG_(generic_match). As
1375 per the spec thereof (see include/pub_tool_seqmatch.h), we
1376 should never get called with a pattern value for which the
1377 _IsStar or _IsQuery function would return True. Hence
1378 this can't happen. */
1381 /* Get the object name into 'caller_name', or "???"
1383 if (!VG_(get_objname)(ip, caller_name, ERRTXT_LEN))
1384 VG_(strcpy)(caller_name, "???");
1387 /* Get the function name into 'caller_name', or "???"
1389 // Nb: C++-mangled names are used in suppressions. Do, though,
1390 // Z-demangle them, since otherwise it's possible to wind
1391 // up comparing "malloc" in the suppression against
1392 // "_vgrZU_libcZdsoZa_malloc" in the backtrace, and the
1393 // two of them need to be made to match.
1394 if (!VG_(get_fnname_no_cxx_demangle)(ip, caller_name, ERRTXT_LEN))
1395 VG_(strcpy)(caller_name, "???");
1401 /* So now we have the function or object name in caller_name, and
1402 the pattern (at the character level) to match against is in
1403 supploc->name. Hence (and leading to a re-entrant call of
1404 VG_(generic_match)): */
1405 return VG_(string_match)(supploc->name, caller_name);
1408 /////////////////////////////////////////////////////
1410 static Bool supp_matches_callers(Error* err, Supp* su)
1412 /* Unwrap the args and set up the correct parameterisation of
1413 VG_(generic_match), using supploc_IsStar, supploc_IsQuery and
1415 /* note, StackTrace === Addr* */
1416 StackTrace ips = VG_(get_ExeContext_StackTrace)(err->where);
1417 UWord n_ips = VG_(get_ExeContext_n_ips)(err->where);
1418 SuppLoc* supps = su->callers;
1419 UWord n_supps = su->n_callers;
1420 UWord szbPatt = sizeof(SuppLoc);
1421 UWord szbInput = sizeof(Addr);
1422 Bool matchAll = False; /* we just want to match a prefix */
1426 /*PATT*/supps, szbPatt, n_supps, 0/*initial Ix*/,
1427 /*INPUT*/ips, szbInput, n_ips, 0/*initial Ix*/,
1428 supploc_IsStar, supploc_IsQuery, supp_pattEQinp
1432 /////////////////////////////////////////////////////
1435 Bool supp_matches_error(Supp* su, Error* err)
1437 switch (su->skind) {
1438 //(example code, see comment on CoreSuppKind above)
1440 // return (err->ekind == ThreadErr);
1442 if (VG_(needs).tool_errors) {
1443 return VG_TDICT_CALL(tool_error_matches_suppression, err, su);
1446 "\nUnhandled suppression type: %u. VG_(needs).tool_errors\n"
1447 "probably needs to be set.\n",
1449 VG_(tool_panic)("unhandled suppression type");
1454 /////////////////////////////////////////////////////
1456 /* Does an error context match a suppression? ie is this a suppressible
1457 error? If so, return a pointer to the Supp record, otherwise NULL.
1458 Tries to minimise the number of symbol searches since they are expensive.
1460 static Supp* is_suppressible_error ( Error* err )
1465 /* stats gathering */
1466 em_supplist_searches++;
1468 /* See if the error context matches any suppression. */
1470 for (su = suppressions; su != NULL; su = su->next) {
1472 if (supp_matches_error(su, err) && supp_matches_callers(err, su)) {
1473 /* got a match. Move this entry to the head of the list
1474 in the hope of making future searches cheaper. */
1476 vg_assert(su_prev->next == su);
1477 su_prev->next = su->next;
1478 su->next = suppressions;
1485 return NULL; /* no matches */
1488 /* Show accumulated error-list and suppression-list search stats.
1490 void VG_(print_errormgr_stats) ( void )
1493 " errormgr: %'lu supplist searches, %'lu comparisons during search\n",
1494 em_supplist_searches, em_supplist_cmps
1497 " errormgr: %'lu errlist searches, %'lu comparisons during search\n",
1498 em_errlist_searches, em_errlist_cmps
1502 /*--------------------------------------------------------------------*/
1504 /*--------------------------------------------------------------------*/