syswrap openat2 for all linux arches
[valgrind.git] / coregrind / m_errormgr.c
blob8f2fc0a965ebb6845fbbb3ea35a521d922fc77f1
2 /*--------------------------------------------------------------------*/
3 /*--- Management of error messages. m_errormgr.c ---*/
4 /*--------------------------------------------------------------------*/
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
10 Copyright (C) 2000-2017 Julian Seward
11 jseward@acm.org
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, see <http://www.gnu.org/licenses/>.
26 The GNU General Public License is contained in the file COPYING.
29 #include "pub_core_basics.h"
30 #include "pub_core_vki.h"
31 #include "pub_core_threadstate.h" // For VG_N_THREADS
32 #include "pub_core_debuginfo.h"
33 #include "pub_core_debuglog.h"
34 #include "pub_core_errormgr.h"
35 #include "pub_core_execontext.h"
36 #include "pub_core_gdbserver.h"
37 #include "pub_core_libcbase.h"
38 #include "pub_core_libcassert.h"
39 #include "pub_core_libcfile.h"
40 #include "pub_core_libcprint.h"
41 #include "pub_core_libcproc.h" // For VG_(getpid)()
42 #include "pub_core_seqmatch.h"
43 #include "pub_core_mallocfree.h"
44 #include "pub_core_options.h"
45 #include "pub_core_stacktrace.h"
46 #include "pub_core_tooliface.h"
47 #include "pub_core_translate.h" // for VG_(translate)()
48 #include "pub_core_xarray.h" // VG_(xaprintf) et al
50 #define DEBUG_ERRORMGR 0 // set to 1 for heavyweight tracing
52 /*------------------------------------------------------------*/
53 /*--- Globals ---*/
54 /*------------------------------------------------------------*/
56 /* After this many different unsuppressed errors have been observed,
57 be more conservative about collecting new ones. */
58 #define M_COLLECT_ERRORS_SLOWLY_AFTER 100
60 /* After this many different unsuppressed errors have been observed,
61 stop collecting errors at all, and tell the user their program is
62 evidently a steaming pile of camel dung. */
63 #define M_COLLECT_NO_ERRORS_AFTER_SHOWN 1000
65 /* After this many total errors have been observed, stop collecting
66 errors at all. Counterpart to M_COLLECT_NO_ERRORS_AFTER_SHOWN. */
67 #define M_COLLECT_NO_ERRORS_AFTER_FOUND 10000000
69 /* The list of error contexts found, both suppressed and unsuppressed.
70 Initially empty, and grows as errors are detected. */
71 static Error* errors = NULL;
73 /* The list of suppression directives, as read from the specified
74 suppressions file. Note that the list gets rearranged as a result
75 of the searches done by is_suppressible_error(). */
76 static Supp* suppressions = NULL;
77 static Bool load_suppressions_called = False;
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 errors shown. */
86 static UInt n_errs_shown = 0;
88 /* Running count of unsuppressed error contexts. */
89 static UInt n_err_contexts = 0;
91 /* Running count of suppressed error contexts. */
92 static UInt n_supp_contexts = 0;
95 /* forwards ... */
96 static Supp* is_suppressible_error ( const Error* err );
98 static ThreadId last_tid_printed = 1;
100 /* Stats: number of searches of the error list initiated. */
101 static UWord em_errlist_searches = 0;
103 /* Stats: number of comparisons done during error list
104 searching. */
105 static UWord em_errlist_cmps = 0;
107 /* Stats: number of searches of the suppression list initiated. */
108 static UWord em_supplist_searches = 0;
110 /* Stats: number of comparisons done during suppression list
111 searching. */
112 static UWord em_supplist_cmps = 0;
114 /*------------------------------------------------------------*/
115 /*--- Error type ---*/
116 /*------------------------------------------------------------*/
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.
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.
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 Int count;
134 // NULL if unsuppressed; or ptr to suppression record.
135 Supp* supp;
137 // The tool-specific part
138 ThreadId tid; // Initialised by core
139 ErrorKind ekind; // Used by ALL. Must be in the range (0..)
140 ExeContext* where; // Initialised by core
141 Addr addr; // Used frequently
142 const HChar* string; // Used frequently
143 void* extra; // For any tool-specific extras
147 ExeContext* VG_(get_error_where) ( const Error* err )
149 return err->where;
152 ErrorKind VG_(get_error_kind) ( const Error* err )
154 return err->ekind;
157 Addr VG_(get_error_address) ( const Error* err )
159 return err->addr;
162 const HChar* VG_(get_error_string) ( const Error* err )
164 return err->string;
167 void* VG_(get_error_extra) ( const Error* err )
169 return err->extra;
172 UInt VG_(get_n_errs_found)( void )
174 return n_errs_found;
177 UInt VG_(get_n_errs_shown)( void )
179 return n_errs_shown;
182 /*------------------------------------------------------------*/
183 /*--- Suppression type ---*/
184 /*------------------------------------------------------------*/
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 */
195 CoreSuppKind;
197 /* Max number of callers for context in a suppression is
198 VG_DEEPEST_BACKTRACE. */
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 SrcName /* Name is of a src file. */
210 SuppLocTy;
212 typedef
213 struct {
214 SuppLocTy ty;
215 Bool name_is_simple_str; /* True if name is a string without
216 '?' and '*' wildcard characters. */
217 HChar* name; /* NULL for NoName and DotDotDot */
218 UInt lineno; /* Valid for SrcName. */
220 SuppLoc;
222 /* Suppressions. Tools can get/set tool-relevant parts with functions
223 declared in include/pub_tool_errormgr.h. Extensible via the 'extra' field.
224 Tools can use a normal enum (with element values in the normal range
225 (0..)) for 'skind'. */
226 struct _Supp {
227 struct _Supp* next;
228 HChar* sname; // The name by which the suppression is referred to.
229 Int count; // The number of times this error has been suppressed.
231 // Index in VG_(clo_suppressions) giving filename from which suppression
232 // was read, and the lineno in this file where sname was read.
233 Int clo_suppressions_i;
234 Int sname_lineno;
236 // Length of 'callers'
237 Int n_callers;
238 // Array of callers, for matching stack traces. First one (name of fn
239 // where err occurs) is mandatory; rest are optional.
240 SuppLoc* callers;
242 /* The tool-specific part */
243 SuppKind skind; // What kind of suppression. Must use the range (0..).
244 HChar* string; // String -- use is optional. NULL by default.
245 void* extra; // Anything else -- use is optional. NULL by default.
248 SuppKind VG_(get_supp_kind) ( const Supp* su )
250 return su->skind;
253 HChar* VG_(get_supp_string) ( const Supp* su )
255 return su->string;
258 void* VG_(get_supp_extra) ( const Supp* su )
260 return su->extra;
264 void VG_(set_supp_kind) ( Supp* su, SuppKind skind )
266 su->skind = skind;
269 void VG_(set_supp_string) ( Supp* su, HChar* string )
271 su->string = string;
274 void VG_(set_supp_extra) ( Supp* su, void* extra )
276 su->extra = extra;
280 /*------------------------------------------------------------*/
281 /*--- Helper fns ---*/
282 /*------------------------------------------------------------*/
284 // Only show core errors if the tool wants to, we're not running with -q,
285 // and were not outputting XML.
286 Bool VG_(showing_core_errors)(void)
288 return VG_(needs).core_errors && VG_(clo_verbosity) >= 1 && !VG_(clo_xml);
291 /* Compare errors, to detect duplicates.
293 static Bool eq_Error ( VgRes res, const Error* e1, const Error* e2 )
295 if (e1->ekind != e2->ekind)
296 return False;
297 if (!VG_(eq_ExeContext)(res, e1->where, e2->where))
298 return False;
300 switch (e1->ekind) {
301 //(example code, see comment on CoreSuppKind above)
302 //case ThreadErr:
303 // vg_assert(VG_(needs).core_errors);
304 // return <something>
305 default:
306 if (VG_(needs).tool_errors) {
307 return VG_TDICT_CALL(tool_eq_Error, res, e1, e2);
308 } else {
309 VG_(printf)("\nUnhandled error type: %u. VG_(needs).tool_errors\n"
310 "probably needs to be set.\n",
311 (UInt)e1->ekind);
312 VG_(core_panic)("unhandled error type");
318 /* Helper functions for suppression generation: print a single line of
319 a suppression pseudo-stack-trace, either in XML or text mode. It's
320 important that the behaviour of these two functions exactly
321 corresponds.
323 #define ERRTXT_LEN 4096
325 static void printSuppForIp_XML(UInt n, DiEpoch ep, Addr ip, void* uu_opaque)
327 const HChar *buf;
328 InlIPCursor* iipc = VG_(new_IIPC)(ep, ip);
329 do {
330 if ( VG_(get_fnname_no_cxx_demangle) (ep, ip, &buf, iipc) ) {
331 VG_(printf_xml)(" <sframe> <fun>%pS</fun> </sframe>\n", buf);
332 } else
333 if ( VG_(get_objname)(ep, ip, &buf) ) {
334 VG_(printf_xml)(" <sframe> <obj>%pS</obj> </sframe>\n", buf);
335 } else {
336 VG_(printf_xml)(" <sframe> <obj>*</obj> </sframe>\n");
338 } while (VG_(next_IIPC)(iipc));
339 VG_(delete_IIPC)(iipc);
342 static void printSuppForIp_nonXML(UInt n, DiEpoch ep, Addr ip, void* textV)
344 const HChar *buf;
345 XArray* /* of HChar */ text = (XArray*)textV;
346 InlIPCursor* iipc = VG_(new_IIPC)(ep, ip);
347 do {
348 if ( VG_(get_fnname_no_cxx_demangle) (ep, ip, &buf, iipc) ) {
349 VG_(xaprintf)(text, " fun:%s\n", buf);
350 } else
351 if ( VG_(get_objname)(ep, ip, &buf) ) {
352 VG_(xaprintf)(text, " obj:%s\n", buf);
353 } else {
354 VG_(xaprintf)(text, " obj:*\n");
356 } while (VG_(next_IIPC)(iipc));
357 VG_(delete_IIPC)(iipc);
360 /* Generate a suppression for an error, either in text or XML mode.
362 static void gen_suppression(const Error* err)
364 const HChar* name;
365 ExeContext* ec;
366 XArray* /* HChar */ text;
368 const HChar* dummy_name = "insert_a_suppression_name_here";
370 vg_assert(err);
372 ec = VG_(get_error_where)(err);
373 vg_assert(ec);
375 name = VG_TDICT_CALL(tool_get_error_name, err);
376 if (NULL == name) {
377 VG_(umsg)("(%s does not allow error to be suppressed)\n",
378 VG_(details).name);
379 return;
382 /* In XML mode, we also need to print the plain text version of the
383 suppresion in a CDATA section. What that really means is, we
384 need to generate the plaintext version both in XML and text
385 mode. So generate it into TEXT. */
386 text = VG_(newXA)( VG_(malloc), "errormgr.gen_suppression.1",
387 VG_(free), sizeof(HChar) );
389 /* Ok. Generate the plain text version into TEXT. */
390 VG_(xaprintf)(text, "{\n");
391 VG_(xaprintf)(text, " <%s>\n", dummy_name);
392 VG_(xaprintf)(text, " %s:%s\n", VG_(details).name, name);
394 HChar *xtra = NULL;
395 SizeT xtra_size = 0;
396 SizeT num_written;
398 do {
399 xtra_size += 256;
400 xtra = VG_(realloc)("errormgr.gen_suppression.2", xtra,xtra_size);
401 num_written = VG_TDICT_CALL(tool_get_extra_suppression_info,
402 err, xtra, xtra_size);
403 } while (num_written == xtra_size); // resize buffer and retry
405 // Ensure buffer is properly terminated
406 vg_assert(xtra[num_written] == '\0');
408 if (num_written)
409 VG_(xaprintf)(text, " %s\n", xtra);
411 // Print stack trace elements
412 UInt n_ips = VG_(get_ExeContext_n_ips)(ec);
413 vg_assert(n_ips > 0);
414 vg_assert(n_ips <= VG_DEEPEST_BACKTRACE);
415 VG_(apply_StackTrace)(printSuppForIp_nonXML,
416 text, VG_(get_ExeContext_epoch)(ec),
417 VG_(get_ExeContext_StackTrace)(ec),
418 n_ips);
420 VG_(xaprintf)(text, "}\n");
421 // zero terminate
422 VG_(xaprintf)(text, "%c", (HChar)0 );
423 // VG_(printf) of text
425 /* And now display it. */
426 if (! VG_(clo_xml) ) {
428 // the simple case
429 VG_(printf)("%s", (HChar*) VG_(indexXA)(text, 0) );
431 } else {
433 /* Now we have to print the XML directly. No need to go to the
434 effort of stuffing it in an XArray, since we won't need it
435 again. */
436 VG_(printf_xml)(" <suppression>\n");
437 VG_(printf_xml)(" <sname>%s</sname>\n", dummy_name);
438 VG_(printf_xml)(
439 " <skind>%pS:%pS</skind>\n", VG_(details).name, name);
440 if (num_written)
441 VG_(printf_xml)(" <skaux>%pS</skaux>\n", xtra);
443 // Print stack trace elements
444 VG_(apply_StackTrace)(printSuppForIp_XML,
445 NULL, VG_(get_ExeContext_epoch)(ec),
446 VG_(get_ExeContext_StackTrace)(ec),
447 VG_(get_ExeContext_n_ips)(ec));
449 // And now the cdata bit
450 // XXX FIXME! properly handle the case where the raw text
451 // itself contains "]]>", as specified in Protocol 4.
452 VG_(printf_xml)(" <rawtext>\n");
453 VG_(printf_xml)("<![CDATA[\n");
454 VG_(printf_xml)("%s", (HChar*) VG_(indexXA)(text, 0) );
455 VG_(printf_xml)("]]>\n");
456 VG_(printf_xml)(" </rawtext>\n");
457 VG_(printf_xml)(" </suppression>\n");
461 VG_(deleteXA)(text);
462 VG_(free)(xtra);
466 /* Figure out if we want to perform a given action for this error,
467 possibly by asking the user.
469 Bool VG_(is_action_requested) ( const HChar* action, Bool* clo )
471 HChar ch, ch2;
472 Int res;
474 /* First off, we shouldn't be asking the user anything if
475 we're in XML mode. */
476 if (VG_(clo_xml))
477 return False; /* That's a Nein, oder Nay as they say down here in B-W */
479 if (*clo == False)
480 return False;
482 VG_(umsg)("\n");
484 again:
485 VG_(printf)(
486 "==%d== "
487 "---- %s ? --- [Return/N/n/Y/y/C/c] ---- ",
488 VG_(getpid)(), action
491 res = VG_(read)(VG_(clo_input_fd), &ch, 1);
492 if (res != 1) goto ioerror;
493 /* res == 1 */
494 if (ch == '\n') return False;
495 if (ch != 'N' && ch != 'n' && ch != 'Y' && ch != 'y'
496 && ch != 'C' && ch != 'c') goto again;
498 res = VG_(read)(VG_(clo_input_fd), &ch2, 1);
499 if (res != 1) goto ioerror;
500 if (ch2 != '\n') goto again;
502 /* No, don't want to do action. */
503 if (ch == 'n' || ch == 'N') return False;
504 /* Yes, want to do action. */
505 if (ch == 'y' || ch == 'Y') return True;
506 /* No, don't want to do action, and don't ask again either. */
507 vg_assert(ch == 'c' || ch == 'C');
509 ioerror:
510 *clo = False;
511 return False;
515 /* Do actions on error, that is, immediately after an error is printed.
516 These are:
517 * possibly, call the GDB server
518 * possibly, generate a suppression.
520 static
521 void do_actions_on_error(const Error* err, Bool allow_db_attach)
523 Bool still_noisy = True;
525 /* if user wants to debug from a certain error nr, then wait for gdb/vgdb */
526 if (VG_(clo_vgdb) != Vg_VgdbNo
527 && allow_db_attach
528 && VG_(clo_vgdb_error) <= n_errs_shown) {
529 if (!(VG_(clo_launched_with_multi)))
530 VG_(umsg)("(action on error) vgdb me ... \n");
531 VG_(gdbserver)( err->tid );
532 if (!(VG_(clo_launched_with_multi)))
533 VG_(umsg)("Continuing ...\n");
536 /* Or maybe we want to generate the error's suppression? */
537 if (VG_(clo_gen_suppressions) == 2
538 || (VG_(clo_gen_suppressions) == 1
539 && VG_(is_action_requested)( "Print suppression", &still_noisy ))
541 gen_suppression(err);
543 if (VG_(clo_gen_suppressions) == 1 && !still_noisy)
544 VG_(clo_gen_suppressions) = 0;
546 if (VG_(clo_exit_on_first_error)) {
547 if (VG_(clo_xml))
548 VG_(printf_xml)("</valgrindoutput>\n");
549 VG_(umsg)("\n");
550 VG_(umsg)("Exit program on first error (--exit-on-first-error=yes)\n");
551 VG_(client_exit)( VG_(clo_error_exitcode) );
556 /* Prints an error. Not entirely simple because of the differences
557 between XML and text mode output.
559 In XML mode:
561 * calls the tool's pre-show method, so the tool can create any
562 preamble ahead of the message, if it wants.
564 * prints the opening tag, and the <unique> and <tid> fields
566 * prints the tool-specific parts of the message
568 * if suppression generation is required, a suppression
570 * the closing tag
572 In text mode:
574 * calls the tool's pre-show method, so the tool can create any
575 preamble ahead of the message, if it wants.
577 * prints the tool-specific parts of the message
579 In both modes:
581 * calls do_actions_on_error. This optionally does a gdbserver call
582 and optionally prints a suppression; both of these may require user input.
584 static void pp_Error ( const Error* err, Bool allow_db_attach, Bool xml )
586 /* If this fails, you probably specified your tool's method
587 dictionary incorrectly. */
588 vg_assert(VG_(needs).tool_errors);
590 if (xml) {
592 /* Ensure that suppression generation is either completely
593 enabled or completely disabled; either way, we won't require
594 any user input. m_main.process_cmd_line_options should
595 ensure the asserted condition holds. */
596 vg_assert( VG_(clo_gen_suppressions) == 0 /* disabled */
597 || VG_(clo_gen_suppressions) == 2 /* for all errors */ );
599 /* Pre-show it to the tool */
600 VG_TDICT_CALL( tool_before_pp_Error, err );
602 /* standard preamble */
603 VG_(printf_xml)("<error>\n");
604 VG_(printf_xml)(" <unique>0x%x</unique>\n", err->unique);
605 VG_(printf_xml)(" <tid>%u</tid>\n", err->tid);
606 ThreadState* tst = VG_(get_ThreadState)(err->tid);
607 if (tst->thread_name) {
608 VG_(printf_xml)(" <threadname>%s</threadname>\n", tst->thread_name);
611 /* actually print it */
612 VG_TDICT_CALL( tool_pp_Error, err );
614 if (VG_(clo_gen_suppressions) > 0)
615 gen_suppression(err);
617 /* postamble */
618 VG_(printf_xml)("</error>\n");
619 VG_(printf_xml)("\n");
621 } else {
623 if (VG_(clo_error_markers)[0])
624 VG_(umsg)("%s\n", VG_(clo_error_markers)[0]);
625 VG_TDICT_CALL( tool_before_pp_Error, err );
627 if (VG_(tdict).tool_show_ThreadIDs_for_errors
628 && err->tid > 0 && err->tid != last_tid_printed) {
629 ThreadState* tst = VG_(get_ThreadState)(err->tid);
630 if (tst->thread_name) {
631 VG_(umsg)("Thread %u %s:\n", err->tid, tst->thread_name );
632 } else {
633 VG_(umsg)("Thread %u:\n", err->tid );
635 last_tid_printed = err->tid;
638 VG_TDICT_CALL( tool_pp_Error, err );
639 VG_(umsg)("\n");
640 if (VG_(clo_error_markers)[1])
641 VG_(umsg)("%s\n", VG_(clo_error_markers)[1]);
645 do_actions_on_error(err, allow_db_attach);
649 /* Construct an error */
650 static
651 void construct_error ( Error* err, ThreadId tid, ErrorKind ekind, Addr a,
652 const HChar* s, void* extra, ExeContext* where )
654 /* DO NOT MAKE unique_counter NON-STATIC */
655 static UInt unique_counter = 0;
657 vg_assert(tid < VG_N_THREADS);
659 /* Core-only parts */
660 err->unique = unique_counter++;
661 err->next = NULL;
662 err->supp = NULL;
663 err->count = 1;
664 err->tid = tid;
665 if (NULL == where)
666 err->where = VG_(record_ExeContext)( tid, 0 );
667 else
668 err->where = where;
670 /* Tool-relevant parts */
671 err->ekind = ekind;
672 err->addr = a;
673 err->extra = extra;
674 err->string = s;
676 /* sanity... */
677 vg_assert( tid < VG_N_THREADS );
682 /* Top-level entry point to the error management subsystem.
683 All detected errors are notified here; this routine decides if/when the
684 user should see the error. */
685 void VG_(maybe_record_error) ( ThreadId tid,
686 ErrorKind ekind, Addr a,
687 const HChar* s, void* extra )
689 Error err;
690 Error* p;
691 Error* p_prev;
692 UInt extra_size;
693 VgRes exe_res = Vg_MedRes;
694 static Bool stopping_message = False;
695 static Bool slowdown_message = False;
697 /* After M_COLLECT_NO_ERRORS_AFTER_SHOWN different errors have
698 been found, or M_COLLECT_NO_ERRORS_AFTER_FOUND total errors
699 have been found, just refuse to collect any more. This stops
700 the burden of the error-management system becoming excessive in
701 extremely buggy programs, although it does make it pretty
702 pointless to continue the Valgrind run after this point. */
703 if (VG_(clo_error_limit)
704 && (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN
705 || n_errs_found >= M_COLLECT_NO_ERRORS_AFTER_FOUND)
706 && !VG_(clo_xml)) {
707 if (!stopping_message) {
708 VG_(umsg)("\n");
710 if (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN) {
711 VG_(umsg)(
712 "More than %d different errors detected. "
713 "I'm not reporting any more.\n",
714 M_COLLECT_NO_ERRORS_AFTER_SHOWN );
715 } else {
716 VG_(umsg)(
717 "More than %d total errors detected. "
718 "I'm not reporting any more.\n",
719 M_COLLECT_NO_ERRORS_AFTER_FOUND );
722 VG_(umsg)("Final error counts will be inaccurate. "
723 "Go fix your program!\n");
724 VG_(umsg)("Rerun with --error-limit=no to disable "
725 "this cutoff. Note\n");
726 VG_(umsg)("that errors may occur in your program without "
727 "prior warning from\n");
728 VG_(umsg)("Valgrind, because errors are no longer "
729 "being displayed.\n");
730 VG_(umsg)("\n");
731 stopping_message = True;
733 return;
736 /* Ignore it if error acquisition is disabled for this thread. */
737 { ThreadState* tst = VG_(get_ThreadState)(tid);
738 if (tst->err_disablement_level > 0)
739 return;
742 /* After M_COLLECT_ERRORS_SLOWLY_AFTER different errors have
743 been found, be much more conservative about collecting new
744 ones. */
745 if (n_errs_shown >= M_COLLECT_ERRORS_SLOWLY_AFTER
746 && !VG_(clo_xml)) {
747 exe_res = Vg_LowRes;
748 if (!slowdown_message) {
749 VG_(umsg)("\n");
750 VG_(umsg)("More than %d errors detected. Subsequent errors\n",
751 M_COLLECT_ERRORS_SLOWLY_AFTER);
752 VG_(umsg)("will still be recorded, but in less "
753 "detail than before.\n");
754 slowdown_message = True;
758 /* Build ourselves the error */
759 construct_error ( &err, tid, ekind, a, s, extra, NULL );
761 /* First, see if we've got an error record matching this one. */
762 em_errlist_searches++;
763 p = errors;
764 p_prev = NULL;
765 while (p != NULL) {
766 em_errlist_cmps++;
767 if (eq_Error(exe_res, p, &err)) {
768 /* Found it. */
769 p->count++;
770 if (p->supp != NULL) {
771 /* Deal correctly with suppressed errors. */
772 p->supp->count++;
773 n_errs_suppressed++;
774 } else {
775 n_errs_found++;
778 /* Move p to the front of the list so that future searches
779 for it are faster. It also allows to print the last
780 error (see VG_(show_last_error). */
781 if (p_prev != NULL) {
782 vg_assert(p_prev->next == p);
783 p_prev->next = p->next;
784 p->next = errors;
785 errors = p;
788 return;
790 p_prev = p;
791 p = p->next;
794 /* Didn't see it. Copy and add. */
796 /* OK, we're really going to collect it. The context is on the stack and
797 will disappear shortly, so we must copy it. First do the main
798 (non-'extra') part.
800 Then VG_(tdict).tool_update_extra can update the 'extra' part. This
801 is for when there are more details to fill in which take time to work
802 out but don't affect our earlier decision to include the error -- by
803 postponing those details until now, we avoid the extra work in the
804 case where we ignore the error. Ugly.
806 Then, if there is an 'extra' part, copy it too, using the size that
807 VG_(tdict).tool_update_extra returned. Also allow for people using
808 the void* extra field for a scalar value like an integer.
811 /* copy main part */
812 p = VG_(malloc)("errormgr.mre.1", sizeof(Error));
813 *p = err;
815 /* update 'extra' */
816 switch (ekind) {
817 //(example code, see comment on CoreSuppKind above)
818 //case ThreadErr:
819 // vg_assert(VG_(needs).core_errors);
820 // extra_size = <something>
821 // break;
822 default:
823 vg_assert(VG_(needs).tool_errors);
824 extra_size = VG_TDICT_CALL(tool_update_extra, p);
825 break;
828 /* copy the error string, if there is one.
829 note: if we would have many errors with big strings, using a
830 DedupPoolAlloc for these strings will avoid duplicating
831 such string in each error using it. */
832 if (NULL != p->string) {
833 p->string = VG_(strdup)("errormgr.mre.2", p->string);
836 /* copy block pointed to by 'extra', if there is one */
837 if (NULL != p->extra && 0 != extra_size) {
838 void* new_extra = VG_(malloc)("errormgr.mre.3", extra_size);
839 VG_(memcpy)(new_extra, p->extra, extra_size);
840 p->extra = new_extra;
843 p->next = errors;
844 p->supp = is_suppressible_error(&err);
845 errors = p;
846 if (p->supp == NULL) {
847 /* update stats */
848 n_err_contexts++;
849 n_errs_found++;
850 n_errs_shown++;
851 /* Actually show the error; more complex than you might think. */
852 pp_Error( p, /*allow_db_attach*/True, VG_(clo_xml) );
853 } else {
854 n_supp_contexts++;
855 n_errs_suppressed++;
856 p->supp->count++;
860 /* Second top-level entry point to the error management subsystem, for
861 errors that the tool wants to report immediately, eg. because they're
862 guaranteed to only happen once. This avoids all the recording and
863 comparing stuff. But they can be suppressed; returns True if it is
864 suppressed. Bool 'print_error' dictates whether to print the error.
865 Bool 'count_error' dictates whether to count the error in n_errs_found.
867 Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind, Addr a, const HChar* s,
868 void* extra, ExeContext* where, Bool print_error,
869 Bool allow_db_attach, Bool count_error )
871 Error err;
872 Supp *su;
874 /* Ignore it if error acquisition is disabled for this thread. */
875 ThreadState* tst = VG_(get_ThreadState)(tid);
876 if (tst->err_disablement_level > 0)
877 return False; /* ignored, not suppressed */
879 /* Build ourselves the error */
880 construct_error ( &err, tid, ekind, a, s, extra, where );
882 /* Unless it's suppressed, we're going to show it. Don't need to make
883 a copy, because it's only temporary anyway.
885 Then update the 'extra' part with VG_(tdict).tool_update_extra),
886 because that can have an affect on whether it's suppressed. Ignore
887 the size return value of VG_(tdict).tool_update_extra, because we're
888 not copying 'extra'. Similarly, 's' is also not copied. */
889 (void)VG_TDICT_CALL(tool_update_extra, &err);
891 su = is_suppressible_error(&err);
892 if (NULL == su) {
893 if (count_error) {
894 n_errs_found++;
895 n_err_contexts++;
898 if (print_error) {
899 /* update stats */
900 n_errs_shown++;
901 /* Actually show the error; more complex than you might think. */
902 pp_Error(&err, allow_db_attach, VG_(clo_xml));
904 return False;
906 } else {
907 if (count_error) {
908 n_errs_suppressed++;
909 n_supp_contexts++;
911 su->count++;
912 return True;
917 /*------------------------------------------------------------*/
918 /*--- Exported fns ---*/
919 /*------------------------------------------------------------*/
921 /* Show the used suppressions. Returns False if no suppression
922 got used. */
923 static Bool show_used_suppressions ( void )
925 Supp *su;
926 Bool any_supp;
928 if (VG_(clo_xml))
929 VG_(printf_xml)("<suppcounts>\n");
931 any_supp = False;
932 for (su = suppressions; su != NULL; su = su->next) {
933 if (su->count <= 0)
934 continue;
935 if (VG_(clo_xml)) {
936 VG_(printf_xml)( " <pair>\n"
937 " <count>%d</count>\n"
938 " <name>%pS</name>\n"
939 " </pair>\n",
940 su->count, su->sname );
941 } else {
942 HChar *xtra = NULL;
943 Int xtra_size = 0;
944 SizeT num_written;
945 // blank line before the first shown suppression, if any
946 if (!any_supp)
947 VG_(dmsg)("\n");
949 do {
950 xtra_size += 256;
951 xtra = VG_(realloc)("errormgr.sus.1", xtra, xtra_size);
952 num_written = VG_TDICT_CALL(tool_print_extra_suppression_use,
953 su, xtra, xtra_size);
954 } while (num_written == xtra_size); // resize buffer and retry
956 // Ensure buffer is properly terminated
957 vg_assert(xtra[num_written] == '\0');
959 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
960 su->clo_suppressions_i);
961 VG_(dmsg)("used_suppression: %6d %s %s:%d%s%s\n", su->count, su->sname,
962 filename,
963 su->sname_lineno,
964 num_written ? " " : "", xtra);
965 VG_(free)(xtra);
967 any_supp = True;
970 if (VG_(clo_xml))
971 VG_(printf_xml)("</suppcounts>\n");
973 return any_supp;
976 /* Show all the errors that occurred, and possibly also the
977 suppressions used. */
978 void VG_(show_all_errors) ( Int verbosity, Bool xml )
980 Int i, n_min;
981 Error *p, *p_min;
982 Bool any_supp;
983 Bool any_error = False;
985 if (verbosity == 0 && !VG_(clo_show_error_list))
986 return;
988 /* If we're printing XML, just show the suppressions and stop. */
989 if (xml) {
990 if (VG_(clo_show_error_list))
991 (void)show_used_suppressions();
992 return;
995 /* We only get here if not printing XML. */
996 VG_(umsg)("ERROR SUMMARY: "
997 "%u errors from %u contexts (suppressed: %u from %u)\n",
998 n_errs_found, n_err_contexts,
999 n_errs_suppressed, n_supp_contexts );
1001 if (!VG_(clo_show_error_list))
1002 return;
1004 // We do the following if VG_(clo_show_error_list)
1005 // or at -v or above, and only in non-XML mode.
1007 /* Print the contexts in order of increasing error count.
1008 Once an error is shown, we add a huge value to its count to filter it
1009 out.
1010 After having shown all errors, we reset count to the original value. */
1011 for (i = 0; i < n_err_contexts; i++) {
1012 n_min = (1 << 30) - 1;
1013 p_min = NULL;
1014 for (p = errors; p != NULL; p = p->next) {
1015 if (p->supp != NULL) continue;
1016 if (p->count < n_min) {
1017 n_min = p->count;
1018 p_min = p;
1021 // XXX: this isn't right. See bug 203651.
1022 if (p_min == NULL) continue; //VG_(core_panic)("show_all_errors()");
1024 any_error = True;
1025 VG_(umsg)("\n");
1026 VG_(umsg)("%d errors in context %d of %u:\n",
1027 p_min->count, i+1, n_err_contexts);
1028 pp_Error( p_min, False/*allow_db_attach*/, False /* xml */ );
1030 // We're not printing XML -- we'd have exited above if so.
1031 vg_assert(! xml);
1033 if ((i+1 == VG_(clo_dump_error))) {
1034 StackTrace ips = VG_(get_ExeContext_StackTrace)(p_min->where);
1035 VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to debugging*/,
1036 ips[0], /*debugging*/True, 0xFE/*verbosity*/,
1037 /*bbs_done*/0,
1038 /*allow redir?*/True);
1041 p_min->count = p_min->count + (1 << 30);
1044 /* reset the counts, otherwise a 2nd call does not show anything anymore */
1045 for (p = errors; p != NULL; p = p->next) {
1046 if (p->count >= (1 << 30))
1047 p->count = p->count - (1 << 30);
1051 any_supp = show_used_suppressions();
1053 if (any_supp)
1054 VG_(umsg)("\n");
1055 // reprint summary, so users don't have to scroll way up to find
1056 // the first printing
1057 if (any_supp || any_error)
1058 VG_(umsg)("ERROR SUMMARY: "
1059 "%u errors from %u contexts (suppressed: %u from %u)\n",
1060 n_errs_found, n_err_contexts, n_errs_suppressed,
1061 n_supp_contexts );
1064 void VG_(show_last_error) ( void )
1066 if (n_err_contexts == 0) {
1067 VG_(umsg)("No errors yet\n");
1068 return;
1071 pp_Error( errors, False/*allow_db_attach*/, False/*xml*/ );
1075 /* Show occurrence counts of all errors, in XML form. */
1076 void VG_(show_error_counts_as_XML) ( void )
1078 Error* err;
1079 VG_(printf_xml)("<errorcounts>\n");
1080 for (err = errors; err != NULL; err = err->next) {
1081 if (err->supp != NULL)
1082 continue;
1083 if (err->count <= 0)
1084 continue;
1085 VG_(printf_xml)(" <pair>\n");
1086 VG_(printf_xml)(" <count>%d</count>\n", err->count);
1087 VG_(printf_xml)(" <unique>0x%x</unique>\n", err->unique);
1088 VG_(printf_xml)(" </pair>\n");
1090 VG_(printf_xml)("</errorcounts>\n");
1091 VG_(printf_xml)("\n");
1095 /*------------------------------------------------------------*/
1096 /*--- Suppression parsing ---*/
1097 /*------------------------------------------------------------*/
1099 /* Get the next char from fd into *out_buf. Returns 1 if success,
1100 0 if eof or < 0 if error. */
1102 static Int get_char ( Int fd, HChar* out_buf )
1104 Int r;
1105 static HChar buf[256];
1106 static Int buf_size = 0;
1107 static Int buf_used = 0;
1108 vg_assert(buf_size >= 0 && buf_size <= sizeof buf);
1109 vg_assert(buf_used >= 0 && buf_used <= buf_size);
1110 if (buf_used == buf_size) {
1111 r = VG_(read)(fd, buf, sizeof buf);
1112 if (r < 0) return r; /* read failed */
1113 vg_assert(r >= 0 && r <= sizeof buf);
1114 buf_size = r;
1115 buf_used = 0;
1117 if (buf_size == 0)
1118 return 0; /* eof */
1119 vg_assert(buf_size >= 0 && buf_size <= sizeof buf);
1120 vg_assert(buf_used >= 0 && buf_used < buf_size);
1121 *out_buf = buf[buf_used];
1122 buf_used++;
1123 return 1;
1126 // Get a non blank non comment line.
1127 // Returns True if eof.
1128 static Bool get_nbnc_line ( Int fd, HChar** bufpp, SizeT* nBufp, Int* lineno )
1130 HChar* buf = *bufpp;
1131 SizeT nBuf = *nBufp;
1132 HChar ch;
1133 Int n, i;
1135 vg_assert(lineno); // lineno needed to correctly track line numbers.
1137 while (True) {
1138 buf[0] = 0;
1139 /* First, read until a non-blank char appears. */
1140 while (True) {
1141 n = get_char(fd, &ch);
1142 if (n == 1 && !VG_(isspace)(ch)) break;
1143 if (n == 1 && ch == '\n')
1144 (*lineno)++;
1145 if (n <= 0) return True;
1148 /* Now, read the line into buf. */
1149 i = 0;
1150 buf[i++] = ch; buf[i] = 0;
1151 while (True) {
1152 n = get_char(fd, &ch);
1153 if (n <= 0) return False; /* the next call will return True */
1154 if (ch == '\n')
1155 (*lineno)++;
1156 if (ch == '\n') break;
1157 if (i > 0 && i == nBuf-1) {
1158 *nBufp = nBuf = nBuf * 2;
1159 #define RIDICULOUS 100000
1160 vg_assert2(nBuf < RIDICULOUS, // Just a sanity check, really.
1161 "VG_(get_line): line longer than %d chars, aborting\n",
1162 RIDICULOUS);
1163 *bufpp = buf = VG_(realloc)("errormgr.get_line.1", buf, nBuf);
1165 buf[i++] = ch; buf[i] = 0;
1167 while (i > 1 && VG_(isspace)(buf[i-1])) {
1168 i--; buf[i] = 0;
1171 // VG_(printf)("The line *%p %d is '%s'\n", lineno, *lineno, buf);
1172 /* Ok, we have a line. If a non-comment line, return.
1173 If a comment line, start all over again. */
1174 if (buf[0] != '#') return False;
1178 // True if buf starts with fun: or obj: or is ...
1179 static Bool is_location_line (const HChar* buf)
1181 return VG_(strncmp)(buf, "fun:", 4) == 0
1182 || VG_(strncmp)(buf, "obj:", 4) == 0
1183 || VG_(strcmp)(buf, "...") == 0;
1186 Bool VG_(get_line) ( Int fd, HChar** bufpp, SizeT* nBufp, Int* lineno )
1188 Bool eof = get_nbnc_line (fd, bufpp, nBufp, lineno);
1190 if (eof)
1191 return True;
1193 if (is_location_line(*bufpp))
1194 return True; // Not a extra suppr line
1195 else
1196 return False; // A suppression extra line
1199 /* True if s contains no wildcard (?, *) characters. */
1200 static Bool is_simple_str (const HChar *s)
1202 while (*s) {
1203 if (*s == '?' || *s == '*')
1204 return False;
1205 s++;
1207 return True;
1210 /* buf contains the raw name of a caller, supposedly either
1211 fun:some_function_name or
1212 obj:some_object_name or
1213 src:some_file_name or
1214 src:some_file_name:line# or
1216 Set p->ty and p->name accordingly.
1217 p->name is allocated and set to the string
1218 after the descriptor (fun:, obj:, or src: san line#) part.
1219 p->lineno is set to non-zero if line# specified; 0 otherwise.
1220 Returns False if failed.
1222 static Bool setLocationTy ( SuppLoc* p, const HChar *buf )
1224 if (VG_(strncmp)(buf, "fun:", 4) == 0) {
1225 p->name = VG_(strdup)("errormgr.sLTy.1", buf+4);
1226 p->name_is_simple_str = is_simple_str (p->name);
1227 p->ty = FunName;
1228 return True;
1230 if (VG_(strncmp)(buf, "obj:", 4) == 0) {
1231 p->name = VG_(strdup)("errormgr.sLTy.2", buf+4);
1232 p->name_is_simple_str = is_simple_str (p->name);
1233 p->ty = ObjName;
1234 return True;
1236 if (VG_(strncmp)(buf, "src:", 4) == 0) {
1237 p->name = VG_(strdup)("errormgr.sLTy.3", buf+4);
1238 p->name_is_simple_str = is_simple_str (p->name);
1239 p->ty = SrcName;
1240 HChar *s = VG_(strchr)(p->name, ':');
1241 if (s != NULL) {
1242 *s++ = '\0'; // trim colon
1243 p->lineno = (UInt) VG_(strtoll10)(s, NULL);
1244 } else {
1245 p->lineno = 0;
1247 return True;
1249 if (VG_(strcmp)(buf, "...") == 0) {
1250 p->name = NULL;
1251 p->name_is_simple_str = False;
1252 p->ty = DotDotDot;
1253 return True;
1255 VG_(printf)("location should be \"...\", or should start "
1256 "with \"fun:\", \"obj:\", or \"src:\"\n");
1257 return False;
1261 /* Look for "tool" in a string like "tool1,tool2,tool3" */
1262 static Bool tool_name_present(const HChar *name, const HChar *names)
1264 Bool found;
1265 HChar *s = NULL; /* Shut gcc up */
1266 Int len = VG_(strlen)(name);
1268 found = (NULL != (s = VG_(strstr)(names, name))
1269 && (s == names || *(s-1) == ',')
1270 && (*(s+len) == ',' || *(s+len) == '\0'));
1272 return found;
1275 /* Read suppressions from the file specified in
1276 VG_(clo_suppressions)[clo_suppressions_i]
1277 and place them in the suppressions list. If there's any difficulty
1278 doing this, just give up -- there's no point in trying to recover.
1280 static void load_one_suppressions_file ( Int clo_suppressions_i )
1282 const HChar* filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1283 clo_suppressions_i);
1284 SysRes sres;
1285 Int fd, i, j, lineno = 0;
1286 Bool got_a_location_line_read_by_tool;
1287 Bool eof;
1288 SizeT nBuf = 200;
1289 HChar* buf = VG_(malloc)("errormgr.losf.1", nBuf);
1290 HChar* tool_names;
1291 HChar* supp_name;
1292 const HChar* err_str = NULL;
1293 SuppLoc tmp_callers[VG_DEEPEST_BACKTRACE];
1295 // Check it's not a directory.
1296 if (VG_(is_dir)( filename )) {
1297 if (VG_(clo_xml))
1298 VG_(printf_xml)("</valgrindoutput>\n");
1299 VG_(umsg)("FATAL: suppressions file \"%s\" is a directory\n", filename );
1300 VG_(exit)(1);
1303 // Open the suppression file.
1304 sres = VG_(open)( filename, VKI_O_RDONLY, 0 );
1305 if (sr_isError(sres)) {
1306 if (VG_(clo_xml))
1307 VG_(printf_xml)("</valgrindoutput>\n");
1308 VG_(umsg)("FATAL: can't open suppressions file \"%s\"\n", filename );
1309 VG_(exit)(1);
1311 fd = sr_Res(sres);
1313 # define BOMB(S) { err_str = S; goto syntax_error; }
1315 while (True) {
1316 /* Assign and initialise the two suppression halves (core and tool) */
1317 Supp* supp;
1318 supp = VG_(malloc)("errormgr.losf.1", sizeof(Supp));
1319 supp->count = 0;
1321 // Initialise temporary reading-in buffer.
1322 for (i = 0; i < VG_DEEPEST_BACKTRACE; i++) {
1323 tmp_callers[i].ty = NoName;
1324 tmp_callers[i].name_is_simple_str = False;
1325 tmp_callers[i].name = NULL;
1328 supp->string = supp->extra = NULL;
1330 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1331 if (eof) {
1332 VG_(free)(supp);
1333 break;
1336 if (!VG_STREQ(buf, "{")) BOMB("expected '{' or end-of-file");
1338 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1340 if (eof || VG_STREQ(buf, "}")) BOMB("unexpected '}'");
1342 supp->sname = VG_(strdup)("errormgr.losf.2", buf);
1343 supp->clo_suppressions_i = clo_suppressions_i;
1344 supp->sname_lineno = lineno;
1346 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1348 if (eof) BOMB("unexpected end-of-file (expecting tool:suppr)");
1350 /* Check it has the "tool1,tool2,...:supp" form (look for ':') */
1351 i = 0;
1352 while (True) {
1353 if (buf[i] == ':') break;
1354 if (buf[i] == '\0') BOMB("malformed 'tool1,tool2,...:supp' line");
1355 i++;
1357 buf[i] = '\0'; /* Replace ':', splitting into two strings */
1359 tool_names = & buf[0];
1360 supp_name = & buf[i+1];
1362 if (VG_(needs).core_errors && tool_name_present("core", tool_names)) {
1363 // A core suppression
1364 //(example code, see comment on CoreSuppKind above)
1365 //if (VG_STREQ(supp_name, "Thread"))
1366 // supp->skind = ThreadSupp;
1367 //else
1368 BOMB("unknown core suppression type");
1370 else if (VG_(needs).tool_errors
1371 && tool_name_present(VG_(details).name, tool_names)) {
1372 // A tool suppression
1373 if (VG_TDICT_CALL(tool_recognised_suppression, supp_name, supp)) {
1374 /* Do nothing, function fills in supp->skind */
1375 } else {
1376 BOMB("unknown tool suppression type");
1379 else {
1380 // Ignore rest of suppression
1381 while (True) {
1382 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1383 if (eof) BOMB("unexpected end-of-file (when skipping suppression)");
1384 if (VG_STREQ(buf, "}"))
1385 break;
1387 VG_(free)(supp->sname);
1388 VG_(free)(supp);
1389 continue;
1392 buf[0] = 0;
1393 // tool_read_extra_suppression_info might read lines
1394 // from fd till a location line.
1395 if (VG_(needs).tool_errors
1396 && !VG_TDICT_CALL(tool_read_extra_suppression_info,
1397 fd, &buf, &nBuf, &lineno, supp)) {
1398 BOMB("bad or missing extra suppression info");
1401 got_a_location_line_read_by_tool = buf[0] != 0 && is_location_line(buf);
1403 /* the main frame-descriptor reading loop */
1404 i = 0;
1405 while (True) {
1406 if (got_a_location_line_read_by_tool) {
1407 got_a_location_line_read_by_tool = False;
1408 eof = False;
1409 } else {
1410 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1412 if (eof)
1413 BOMB("unexpected end-of-file (when reading stack trace)");
1414 if (VG_STREQ(buf, "}")) {
1415 if (i > 0) {
1416 break;
1417 } else {
1418 BOMB("missing stack trace");
1421 if (i == VG_DEEPEST_BACKTRACE)
1422 BOMB("too many callers in stack trace");
1423 if (i > 0 && i >= VG_(clo_backtrace_size))
1424 break;
1425 if (!setLocationTy(&(tmp_callers[i]), buf))
1426 BOMB("location should be \"...\", or should start "
1427 "with \"fun:\", \"obj:\", or \"src:\"");
1428 i++;
1431 // If the num callers is >= VG_(clo_backtrace_size), ignore any extra
1432 // lines and grab the '}'.
1433 if (!VG_STREQ(buf, "}")) {
1434 do {
1435 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1436 } while (!eof && !VG_STREQ(buf, "}"));
1439 // Reject entries which are entirely composed of frame
1440 // level wildcards.
1441 vg_assert(i > 0); // guaranteed by frame-descriptor reading loop
1442 for (j = 0; j < i; j++) {
1443 if (tmp_callers[j].ty == FunName || tmp_callers[j].ty == ObjName
1444 || tmp_callers[j].ty == SrcName) {
1445 break;
1447 vg_assert(tmp_callers[j].ty == DotDotDot);
1449 vg_assert(j >= 0 && j <= i);
1450 if (j == i) {
1451 // we didn't find any non-"..." entries
1452 BOMB("suppression must contain at least one location "
1453 "line which is not \"...\"");
1456 // Copy tmp_callers[] into supp->callers[]
1457 supp->n_callers = i;
1458 supp->callers = VG_(malloc)("errormgr.losf.4", i * sizeof(SuppLoc));
1459 for (i = 0; i < supp->n_callers; i++) {
1460 supp->callers[i] = tmp_callers[i];
1463 supp->next = suppressions;
1464 suppressions = supp;
1466 VG_(free)(buf);
1467 VG_(close)(fd);
1468 return;
1470 syntax_error:
1471 if (VG_(clo_xml))
1472 VG_(printf_xml)("</valgrindoutput>\n");
1473 VG_(umsg)("FATAL: in suppressions file \"%s\" near line %d:\n",
1474 filename, lineno );
1475 VG_(umsg)(" %s\n", err_str );
1477 VG_(close)(fd);
1478 VG_(umsg)("exiting now.\n");
1479 VG_(exit)(1);
1481 # undef BOMB
1484 void VG_(add_suppression_file)(const HChar *filename)
1486 HChar *f = VG_(strdup)("errormgr.addsup", filename);
1487 VG_(addToXA)(VG_(clo_suppressions), &f);
1488 if (load_suppressions_called)
1489 load_one_suppressions_file( VG_(sizeXA)(VG_(clo_suppressions)) - 1 );
1492 void VG_(load_suppressions) ( void )
1494 Int i;
1495 suppressions = NULL;
1496 load_suppressions_called = True;
1497 for (i = 0; i < VG_(sizeXA)(VG_(clo_suppressions)); i++) {
1498 if (VG_(clo_verbosity) > 1) {
1499 VG_(dmsg)("Reading suppressions file: %s\n",
1500 *(HChar**) VG_(indexXA)(VG_(clo_suppressions), i));
1502 load_one_suppressions_file( i );
1507 /*------------------------------------------------------------*/
1508 /*--- Matching errors to suppressions ---*/
1509 /*------------------------------------------------------------*/
1511 /* Parameterising functions for the use of VG_(generic_match) in
1512 suppression-vs-error matching. The suppression frames (SuppLoc)
1513 play the role of 'pattern'-element, and the error frames (IPs,
1514 hence simply Addrs) play the role of 'input'. In short then, we're
1515 matching a sequence of Addrs against a pattern composed of a
1516 sequence of SuppLocs.
1518 static Bool supploc_IsStar ( const void* supplocV )
1520 const SuppLoc* supploc = supplocV;
1521 return supploc->ty == DotDotDot;
1524 static Bool supploc_IsQuery ( const void* supplocV )
1526 return False; /* there's no '?' equivalent in the supp syntax */
1529 /* IPtoFunOrObjCompleter is a lazy completer of the IPs
1530 needed to match an error with the suppression patterns.
1531 The matching between an IP and a suppression pattern is done either
1532 with the IP function name or with the IP object name.
1533 First time the fun or obj name is needed for an IP member
1534 of a stack trace, it will be computed and stored in names.
1535 Also, if the IP corresponds to one or more inlined function calls,
1536 the inlined function names are expanded.
1537 The IPtoFunOrObjCompleter type is designed to minimise the nr of
1538 allocations and the nr of debuginfo search. */
1539 typedef
1540 struct {
1541 DiEpoch epoch; // used to interpret .ips
1542 StackTrace ips; // stack trace we are lazily completing.
1543 UWord n_ips; // nr of elements in ips.
1545 // VG_(generic_match) calls haveInputInpC to check
1546 // for the presence of an input element identified by ixInput
1547 // (i.e. a number that identifies the ixInput element of the
1548 // input sequence). It calls supp_pattEQinp to match this input
1549 // element with a pattern.
1550 // When inlining info is used to provide inlined function calls
1551 // in stacktraces, one IP in ips can be expanded in several
1552 // function names. So, each time input (or presence of input)
1553 // is requested by VG_(generic_match), we will expand
1554 // more IP of ips till we have expanded enough to reach the
1555 // input element requested (or we cannot expand anymore).
1557 UWord n_ips_expanded;
1558 // n_ips_expanded maintains the nr of elements in ips that we have
1559 // already expanded.
1560 UWord n_expanded;
1561 // n_expanded maintains the nr of elements resulting from the expansion
1562 // of the n_ips_expanded IPs. Without inlined function calls,
1563 // n_expanded == n_ips_expanded. With inlining info,
1564 // n_expanded >= n_ips_expanded.
1566 Int* n_offsets_per_ip;
1567 // n_offsets_per_ip[i] gives the nr of offsets in fun_offsets and
1568 // obj_offsets resulting of the expansion of ips[i].
1569 // The sum of all n_expanded_per_ip must be equal to n_expanded.
1570 // This array allows to retrieve the position in ips corresponding to
1571 // an ixInput.
1573 // size (in elements) of fun_offsets and obj_offsets.
1574 // (fun|obj)_offsets are reallocated if more space is needed
1575 // to expand an IP.
1576 UWord sz_offsets;
1578 Int* fun_offsets;
1579 // fun_offsets[ixInput] is the offset in names where the
1580 // function name for the ixInput element of the input sequence
1581 // can be found. As one IP of ips can be expanded in several
1582 // function calls due to inlined function calls, we can have more
1583 // elements in fun_offsets than in ips.
1584 // An offset -1 means the function name has not yet been computed.
1585 Int* obj_offsets;
1586 // Similarly, obj_offsets[ixInput] gives the offset for the
1587 // object name for ips[ixInput]
1588 // (-1 meaning object name not yet been computed).
1590 // All function names and object names will be concatenated
1591 // in names. names is reallocated on demand.
1592 HChar *names;
1593 Int names_szB; // size of names.
1594 Int names_free; // offset first free HChar in names.
1596 IPtoFunOrObjCompleter;
1598 static void pp_ip2fo (const IPtoFunOrObjCompleter* ip2fo)
1600 Int i, j;
1601 Int o;
1603 VG_(printf)("n_ips %lu n_ips_expanded %lu resulting in n_expanded %lu\n",
1604 ip2fo->n_ips, ip2fo->n_ips_expanded, ip2fo->n_expanded);
1605 for (i = 0; i < ip2fo->n_ips_expanded; i++) {
1606 o = 0;
1607 for (j = 0; j < i; j++)
1608 o += ip2fo->n_offsets_per_ip[j];
1609 VG_(printf)("ips %d 0x08%lx offset [%d,%d] ",
1610 i, ip2fo->ips[i],
1611 o, o+ip2fo->n_offsets_per_ip[i]-1);
1612 for (j = 0; j < ip2fo->n_offsets_per_ip[i]; j++) {
1613 VG_(printf)("%sfun:%s obj:%s\n",
1614 j == 0 ? "" : " ",
1615 ip2fo->fun_offsets[o+j] == -1 ?
1616 "<not expanded>" : &ip2fo->names[ip2fo->fun_offsets[o+j]],
1617 ip2fo->obj_offsets[o+j] == -1 ?
1618 "<not expanded>" : &ip2fo->names[ip2fo->obj_offsets[o+j]]);
1623 /* free the memory in ip2fo.
1624 At debuglog 4, su (or NULL) will be used to show the matching
1625 (or non matching) with ip2fo. */
1626 static void clearIPtoFunOrObjCompleter ( const Supp *su,
1627 IPtoFunOrObjCompleter* ip2fo)
1629 if (DEBUG_ERRORMGR || VG_(debugLog_getLevel)() >= 4) {
1630 if (su) {
1631 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1632 su->clo_suppressions_i);
1633 VG_(dmsg)("errormgr matching end suppression %s %s:%d matched:\n",
1634 su->sname,
1635 filename,
1636 su->sname_lineno);
1637 } else {
1638 VG_(dmsg)("errormgr matching end no suppression matched:\n");
1640 VG_(pp_StackTrace) (ip2fo->epoch, ip2fo->ips, ip2fo->n_ips);
1641 pp_ip2fo(ip2fo);
1643 if (ip2fo->n_offsets_per_ip) VG_(free)(ip2fo->n_offsets_per_ip);
1644 if (ip2fo->fun_offsets) VG_(free)(ip2fo->fun_offsets);
1645 if (ip2fo->obj_offsets) VG_(free)(ip2fo->obj_offsets);
1646 if (ip2fo->names) VG_(free)(ip2fo->names);
1649 /* Grow ip2fo->names to ensure we have NEEDED characters available
1650 in ip2fo->names and returns a pointer to the first free char. */
1651 static HChar* grow_names(IPtoFunOrObjCompleter* ip2fo, SizeT needed)
1653 if (ip2fo->names_szB
1654 < ip2fo->names_free + needed) {
1655 if (needed < ERRTXT_LEN) needed = ERRTXT_LEN;
1657 ip2fo->names
1658 = VG_(realloc)("foc_names",
1659 ip2fo->names,
1660 ip2fo->names_szB + needed);
1661 ip2fo->names_szB += needed;
1663 return ip2fo->names + ip2fo->names_free;
1666 /* foComplete returns the function name or object name for ixInput.
1667 If needFun, returns the function name for this input
1668 else returns the object name for this input.
1669 The function name or object name will be computed and added in
1670 names if not yet done. */
1671 static HChar* foComplete(IPtoFunOrObjCompleter* ip2fo,
1672 Int ixInput, Bool needFun)
1674 vg_assert (ixInput < ip2fo->n_expanded);
1675 vg_assert (VG_(clo_read_inline_info) || ixInput < ip2fo->n_ips);
1677 // ptr to the offset array for function offsets (if needFun)
1678 // or object offsets (if !needFun).
1679 Int** offsets;
1680 if (needFun)
1681 offsets = &ip2fo->fun_offsets;
1682 else
1683 offsets = &ip2fo->obj_offsets;
1685 // Complete Fun name or Obj name for IP if not yet done.
1686 if ((*offsets)[ixInput] == -1) {
1687 const HChar* caller;
1689 (*offsets)[ixInput] = ip2fo->names_free;
1690 if (DEBUG_ERRORMGR) VG_(printf)("marking %s ixInput %d offset %d\n",
1691 needFun ? "fun" : "obj",
1692 ixInput, ip2fo->names_free);
1693 if (needFun) {
1694 // With inline info, fn names must have been completed already.
1695 vg_assert (!VG_(clo_read_inline_info));
1696 /* Get the function name into 'caller_name', or "???"
1697 if unknown. */
1698 // Nb: C++-mangled names are used in suppressions. Do, though,
1699 // Z-demangle them, since otherwise it's possible to wind
1700 // up comparing "malloc" in the suppression against
1701 // "_vgrZU_libcZdsoZa_malloc" in the backtrace, and the
1702 // two of them need to be made to match.
1703 if (!VG_(get_fnname_no_cxx_demangle)(ip2fo->epoch,
1704 ip2fo->ips[ixInput],
1705 &caller,
1706 NULL))
1707 caller = "???";
1708 } else {
1709 /* Get the object name into 'caller_name', or "???"
1710 if unknown. */
1711 UWord i;
1712 UWord last_expand_pos_ips = 0;
1713 UWord pos_ips;
1715 /* First get the pos in ips corresponding to ixInput */
1716 for (pos_ips = 0; pos_ips < ip2fo->n_expanded; pos_ips++) {
1717 last_expand_pos_ips += ip2fo->n_offsets_per_ip[pos_ips];
1718 if (ixInput < last_expand_pos_ips)
1719 break;
1721 /* pos_ips is the position in ips corresponding to ixInput.
1722 last_expand_pos_ips is the last offset in fun/obj where
1723 ips[pos_ips] has been expanded. */
1725 if (!VG_(get_objname)(ip2fo->epoch, ip2fo->ips[pos_ips], &caller))
1726 caller = "???";
1728 // Have all inlined calls pointing at this object name
1729 for (i = last_expand_pos_ips - ip2fo->n_offsets_per_ip[pos_ips] + 1;
1730 i < last_expand_pos_ips;
1731 i++) {
1732 ip2fo->obj_offsets[i] = ip2fo->names_free;
1733 if (DEBUG_ERRORMGR)
1734 VG_(printf) (" set obj_offset %lu to %d\n",
1735 i, ip2fo->names_free);
1738 SizeT caller_len = VG_(strlen)(caller);
1739 HChar* caller_name = grow_names(ip2fo, caller_len + 1);
1740 VG_(strcpy)(caller_name, caller);
1741 ip2fo->names_free += caller_len + 1;
1742 if (DEBUG_ERRORMGR) pp_ip2fo(ip2fo);
1745 return ip2fo->names + (*offsets)[ixInput];
1748 // Grow fun and obj _offsets arrays to have at least n_req elements.
1749 // Ensure n_offsets_per_ip is allocated.
1750 static void grow_offsets(IPtoFunOrObjCompleter* ip2fo, Int n_req)
1752 Int i;
1754 // n_offsets_per_ip must always have the size of the ips array
1755 if (ip2fo->n_offsets_per_ip == NULL) {
1756 ip2fo->n_offsets_per_ip = VG_(malloc)("grow_offsets",
1757 ip2fo->n_ips * sizeof(Int));
1758 for (i = 0; i < ip2fo->n_ips; i++)
1759 ip2fo->n_offsets_per_ip[i] = 0;
1762 if (ip2fo->sz_offsets >= n_req)
1763 return;
1765 // Avoid too much re-allocation by allocating at least ip2fo->n_ips
1766 // elements and at least a few more elements than the current size.
1767 if (n_req < ip2fo->n_ips)
1768 n_req = ip2fo->n_ips;
1769 if (n_req < ip2fo->sz_offsets + 5)
1770 n_req = ip2fo->sz_offsets + 5;
1772 ip2fo->fun_offsets = VG_(realloc)("grow_offsets", ip2fo->fun_offsets,
1773 n_req * sizeof(Int));
1774 for (i = ip2fo->sz_offsets; i < n_req; i++)
1775 ip2fo->fun_offsets[i] = -1;
1777 ip2fo->obj_offsets = VG_(realloc)("grow_offsets", ip2fo->obj_offsets,
1778 n_req * sizeof(Int));
1779 for (i = ip2fo->sz_offsets; i < n_req; i++)
1780 ip2fo->obj_offsets[i] = -1;
1782 ip2fo->sz_offsets = n_req;
1785 // Expands more IPs from ip2fo->ips.
1786 static void expandInput (IPtoFunOrObjCompleter* ip2fo, UWord ixInput )
1788 while (ip2fo->n_ips_expanded < ip2fo->n_ips
1789 && ip2fo->n_expanded <= ixInput) {
1790 if (VG_(clo_read_inline_info)) {
1791 // Expand one more IP in one or more calls.
1792 const Addr IP = ip2fo->ips[ip2fo->n_ips_expanded];
1793 InlIPCursor *iipc;
1795 iipc = VG_(new_IIPC)(ip2fo->epoch, IP);
1796 // The only thing we really need is the nr of inlined fn calls
1797 // corresponding to the IP we will expand.
1798 // However, computing this is mostly the same as finding
1799 // the function name. So, let's directly complete the function name.
1800 do {
1801 const HChar *caller;
1802 grow_offsets(ip2fo, ip2fo->n_expanded+1);
1803 ip2fo->fun_offsets[ip2fo->n_expanded] = ip2fo->names_free;
1804 if (!VG_(get_fnname_no_cxx_demangle)(ip2fo->epoch, IP,
1805 &caller,
1806 iipc))
1807 caller = "???";
1808 SizeT caller_len = VG_(strlen)(caller);
1809 HChar* caller_name = grow_names(ip2fo, caller_len + 1);
1810 VG_(strcpy)(caller_name, caller);
1811 ip2fo->names_free += caller_len + 1;
1812 ip2fo->n_expanded++;
1813 ip2fo->n_offsets_per_ip[ip2fo->n_ips_expanded]++;
1814 } while (VG_(next_IIPC)(iipc));
1815 ip2fo->n_ips_expanded++;
1816 VG_(delete_IIPC) (iipc);
1817 } else {
1818 // Without inlined fn call info, expansion simply
1819 // consists in allocating enough elements in (fun|obj)_offsets.
1820 // The function or object names themselves will be completed
1821 // when requested.
1822 Int i;
1823 grow_offsets(ip2fo, ip2fo->n_ips);
1824 ip2fo->n_ips_expanded = ip2fo->n_ips;
1825 ip2fo->n_expanded = ip2fo->n_ips;
1826 for (i = 0; i < ip2fo->n_ips; i++)
1827 ip2fo->n_offsets_per_ip[i] = 1;
1832 static Bool haveInputInpC (void* inputCompleterV, UWord ixInput )
1834 IPtoFunOrObjCompleter* ip2fo = (IPtoFunOrObjCompleter*)inputCompleterV;
1835 expandInput(ip2fo, ixInput);
1836 return ixInput < ip2fo->n_expanded;
1839 static Bool supp_pattEQinp ( const void* supplocV, const void* addrV,
1840 void* inputCompleterV, UWord ixInput )
1842 const SuppLoc* supploc = (const SuppLoc*)supplocV; /* PATTERN */
1843 IPtoFunOrObjCompleter* ip2fo = (IPtoFunOrObjCompleter*)inputCompleterV;
1844 const HChar* funobjsrc_name; // Fun, Obj, or src file name.
1845 UInt src_lineno = 0;
1846 Bool ret;
1848 expandInput(ip2fo, ixInput);
1849 vg_assert(ixInput < ip2fo->n_expanded);
1851 /* So, does this IP address match this suppression-line? */
1852 switch (supploc->ty) {
1853 case DotDotDot:
1854 /* supp_pattEQinp is a callback from VG_(generic_match). As
1855 per the spec thereof (see include/pub_tool_seqmatch.h), we
1856 should never get called with a pattern value for which the
1857 _IsStar or _IsQuery function would return True. Hence
1858 this can't happen. */
1859 vg_assert(0);
1860 case ObjName:
1861 funobjsrc_name = foComplete(ip2fo, ixInput, False /*needFun*/);
1862 break;
1863 case FunName:
1864 funobjsrc_name = foComplete(ip2fo, ixInput, True /*needFun*/);
1865 break;
1866 case SrcName: {
1867 const HChar* src_dirname; // placeholder only
1868 ret = VG_(get_filename_linenum)(VG_(current_DiEpoch)(),
1869 ip2fo->ips[ixInput], &funobjsrc_name, &src_dirname, &src_lineno);
1870 if (!ret) {
1871 /* No file name found for location so no way this is a match. */
1872 return ret;
1874 break;
1876 default:
1877 vg_assert(0);
1880 /* So now we have the function or object name in funobjsrc_name, and
1881 the pattern (at the character level) to match against is in
1882 supploc->name. Hence (and leading to a re-entrant call of
1883 VG_(generic_match) if there is a wildcard character): */
1884 if (supploc->name_is_simple_str)
1885 ret = VG_(strcmp) (supploc->name, funobjsrc_name) == 0;
1886 else
1887 ret = VG_(string_match)(supploc->name, funobjsrc_name);
1888 if (ret && supploc->ty == SrcName && supploc->lineno != 0) {
1889 ret = (supploc->lineno == src_lineno);
1891 if (DEBUG_ERRORMGR)
1892 VG_(printf) ("supp_pattEQinp %s patt %s ixInput %lu value:%s (lineno:%u vs %u) match:%s\n",
1893 supploc->ty == FunName ? "fun" : (supploc->ty == SrcName ? "src" : "obj"),
1894 supploc->name, ixInput, funobjsrc_name,
1895 supploc->ty == SrcName ? supploc->lineno : 0,
1896 supploc->ty == SrcName ? src_lineno : 0,
1897 ret ? "yes" : "no");
1898 return ret;
1901 /////////////////////////////////////////////////////
1903 static Bool supp_matches_callers(IPtoFunOrObjCompleter* ip2fo,
1904 const Supp* su)
1906 /* Unwrap the args and set up the correct parameterisation of
1907 VG_(generic_match), using supploc_IsStar, supploc_IsQuery and
1908 supp_pattEQinp. */
1909 /* note, StackTrace ip2fo->ips === Addr* */
1910 SuppLoc* supps = su->callers;
1911 UWord n_supps = su->n_callers;
1912 UWord szbPatt = sizeof(SuppLoc);
1913 Bool matchAll = False; /* we just want to match a prefix */
1914 if (DEBUG_ERRORMGR) {
1915 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1916 su->clo_suppressions_i);
1917 VG_(dmsg)(" errormgr Checking match with %s %s:%d\n",
1918 su->sname,
1919 filename,
1920 su->sname_lineno);
1922 return
1923 VG_(generic_match)(
1924 matchAll,
1925 /*PATT*/supps, szbPatt, n_supps, 0/*initial ixPatt*/,
1926 /*INPUT*/
1927 NULL, 0, 0, /* input/szbInput/nInput 0, as using an inputCompleter */
1928 0/*initial ixInput*/,
1929 supploc_IsStar, supploc_IsQuery, supp_pattEQinp,
1930 ip2fo, haveInputInpC
1934 /////////////////////////////////////////////////////
1936 static
1937 Bool supp_matches_error(const Supp* su, const Error* err)
1939 switch (su->skind) {
1940 //(example code, see comment on CoreSuppKind above)
1941 //case ThreadSupp:
1942 // return (err->ekind == ThreadErr);
1943 default:
1944 if (VG_(needs).tool_errors) {
1945 return VG_TDICT_CALL(tool_error_matches_suppression, err, su);
1946 } else {
1947 VG_(printf)(
1948 "\nUnhandled suppression type: %u. VG_(needs).tool_errors\n"
1949 "probably needs to be set.\n",
1950 (UInt)err->ekind);
1951 VG_(core_panic)("unhandled suppression type");
1956 /////////////////////////////////////////////////////
1958 /* Does an error context match a suppression? ie is this a suppressible
1959 error? If so, return a pointer to the Supp record, otherwise NULL.
1960 Tries to minimise the number of symbol searches since they are expensive.
1962 static Supp* is_suppressible_error ( const Error* err )
1964 Supp* su;
1965 Supp* su_prev;
1967 IPtoFunOrObjCompleter ip2fo;
1968 /* Conceptually, ip2fo contains an array of function names and an array of
1969 object names, corresponding to the array of IP of err->where.
1970 These names are just computed 'on demand' (so once maximum),
1971 then stored (efficiently, avoiding too many allocs) in ip2fo to be
1972 re-usable for the matching of the same IP with the next suppression
1973 pattern.
1975 VG_(generic_match) gets this 'IP to Fun or Obj name completer' as one
1976 of its arguments. It will then pass it to the function
1977 supp_pattEQinp which will then lazily complete the IP function name or
1978 object name inside ip2fo. Next time the fun or obj name for the same
1979 IP is needed (i.e. for the matching with the next suppr pattern), then
1980 the fun or obj name will not be searched again in the debug info. */
1982 /* stats gathering */
1983 em_supplist_searches++;
1985 /* Prepare the lazy input completer. */
1986 ip2fo.epoch = VG_(get_ExeContext_epoch)(err->where);
1987 ip2fo.ips = VG_(get_ExeContext_StackTrace)(err->where);
1988 ip2fo.n_ips = VG_(get_ExeContext_n_ips)(err->where);
1989 ip2fo.n_ips_expanded = 0;
1990 ip2fo.n_expanded = 0;
1991 ip2fo.sz_offsets = 0;
1992 ip2fo.n_offsets_per_ip = NULL;
1993 ip2fo.fun_offsets = NULL;
1994 ip2fo.obj_offsets = NULL;
1995 ip2fo.names = NULL;
1996 ip2fo.names_szB = 0;
1997 ip2fo.names_free = 0;
1999 /* See if the error context matches any suppression. */
2000 if (DEBUG_ERRORMGR || VG_(debugLog_getLevel)() >= 4)
2001 VG_(dmsg)("errormgr matching begin\n");
2002 su_prev = NULL;
2003 for (su = suppressions; su != NULL; su = su->next) {
2004 em_supplist_cmps++;
2005 if (supp_matches_error(su, err)
2006 && supp_matches_callers(&ip2fo, su)) {
2007 /* got a match. */
2008 /* Inform the tool that err is suppressed by su. */
2009 (void)VG_TDICT_CALL(tool_update_extra_suppression_use, err, su);
2010 /* Move this entry to the head of the list
2011 in the hope of making future searches cheaper. */
2012 if (su_prev) {
2013 vg_assert(su_prev->next == su);
2014 su_prev->next = su->next;
2015 su->next = suppressions;
2016 suppressions = su;
2018 clearIPtoFunOrObjCompleter(su, &ip2fo);
2019 return su;
2021 su_prev = su;
2023 clearIPtoFunOrObjCompleter(NULL, &ip2fo);
2024 return NULL; /* no matches */
2027 /* Show accumulated error-list and suppression-list search stats.
2029 void VG_(print_errormgr_stats) ( void )
2031 VG_(dmsg)(
2032 " errormgr: %'lu supplist searches, %'lu comparisons during search\n",
2033 em_supplist_searches, em_supplist_cmps
2035 VG_(dmsg)(
2036 " errormgr: %'lu errlist searches, %'lu comparisons during search\n",
2037 em_errlist_searches, em_errlist_cmps
2041 /*--------------------------------------------------------------------*/
2042 /*--- end ---*/
2043 /*--------------------------------------------------------------------*/