vgdb: Handle EAGAIN in read_buf
[valgrind.git] / coregrind / m_errormgr.c
blob6be637190aae8ce4c8d92dfe82f37e6d7e9e079d
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 ExeContext* where; // Initialised by core
140 ErrorKind ekind; // Used by ALL. Must be in the range (0..)
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 VG_(umsg)("(action on error) vgdb me ... \n");
530 VG_(gdbserver)( err->tid );
531 VG_(umsg)("Continuing ...\n");
534 /* Or maybe we want to generate the error's suppression? */
535 if (VG_(clo_gen_suppressions) == 2
536 || (VG_(clo_gen_suppressions) == 1
537 && VG_(is_action_requested)( "Print suppression", &still_noisy ))
539 gen_suppression(err);
541 if (VG_(clo_gen_suppressions) == 1 && !still_noisy)
542 VG_(clo_gen_suppressions) = 0;
544 if (VG_(clo_exit_on_first_error)) {
545 if (VG_(clo_xml))
546 VG_(printf_xml)("</valgrindoutput>\n");
547 VG_(umsg)("\n");
548 VG_(umsg)("Exit program on first error (--exit-on-first-error=yes)\n");
549 VG_(client_exit)( VG_(clo_error_exitcode) );
554 /* Prints an error. Not entirely simple because of the differences
555 between XML and text mode output.
557 In XML mode:
559 * calls the tool's pre-show method, so the tool can create any
560 preamble ahead of the message, if it wants.
562 * prints the opening tag, and the <unique> and <tid> fields
564 * prints the tool-specific parts of the message
566 * if suppression generation is required, a suppression
568 * the closing tag
570 In text mode:
572 * calls the tool's pre-show method, so the tool can create any
573 preamble ahead of the message, if it wants.
575 * prints the tool-specific parts of the message
577 In both modes:
579 * calls do_actions_on_error. This optionally does a gdbserver call
580 and optionally prints a suppression; both of these may require user input.
582 static void pp_Error ( const Error* err, Bool allow_db_attach, Bool xml )
584 /* If this fails, you probably specified your tool's method
585 dictionary incorrectly. */
586 vg_assert(VG_(needs).tool_errors);
588 if (xml) {
590 /* Ensure that suppression generation is either completely
591 enabled or completely disabled; either way, we won't require
592 any user input. m_main.process_cmd_line_options should
593 ensure the asserted condition holds. */
594 vg_assert( VG_(clo_gen_suppressions) == 0 /* disabled */
595 || VG_(clo_gen_suppressions) == 2 /* for all errors */ );
597 /* Pre-show it to the tool */
598 VG_TDICT_CALL( tool_before_pp_Error, err );
600 /* standard preamble */
601 VG_(printf_xml)("<error>\n");
602 VG_(printf_xml)(" <unique>0x%x</unique>\n", err->unique);
603 VG_(printf_xml)(" <tid>%u</tid>\n", err->tid);
604 ThreadState* tst = VG_(get_ThreadState)(err->tid);
605 if (tst->thread_name) {
606 VG_(printf_xml)(" <threadname>%s</threadname>\n", tst->thread_name);
609 /* actually print it */
610 VG_TDICT_CALL( tool_pp_Error, err );
612 if (VG_(clo_gen_suppressions) > 0)
613 gen_suppression(err);
615 /* postamble */
616 VG_(printf_xml)("</error>\n");
617 VG_(printf_xml)("\n");
619 } else {
621 if (VG_(clo_error_markers)[0])
622 VG_(umsg)("%s\n", VG_(clo_error_markers)[0]);
623 VG_TDICT_CALL( tool_before_pp_Error, err );
625 if (VG_(tdict).tool_show_ThreadIDs_for_errors
626 && err->tid > 0 && err->tid != last_tid_printed) {
627 ThreadState* tst = VG_(get_ThreadState)(err->tid);
628 if (tst->thread_name) {
629 VG_(umsg)("Thread %u %s:\n", err->tid, tst->thread_name );
630 } else {
631 VG_(umsg)("Thread %u:\n", err->tid );
633 last_tid_printed = err->tid;
636 VG_TDICT_CALL( tool_pp_Error, err );
637 VG_(umsg)("\n");
638 if (VG_(clo_error_markers)[1])
639 VG_(umsg)("%s\n", VG_(clo_error_markers)[1]);
643 do_actions_on_error(err, allow_db_attach);
647 /* Construct an error */
648 static
649 void construct_error ( Error* err, ThreadId tid, ErrorKind ekind, Addr a,
650 const HChar* s, void* extra, ExeContext* where )
652 /* DO NOT MAKE unique_counter NON-STATIC */
653 static UInt unique_counter = 0;
655 vg_assert(tid < VG_N_THREADS);
657 /* Core-only parts */
658 err->unique = unique_counter++;
659 err->next = NULL;
660 err->supp = NULL;
661 err->count = 1;
662 err->tid = tid;
663 if (NULL == where)
664 err->where = VG_(record_ExeContext)( tid, 0 );
665 else
666 err->where = where;
668 /* Tool-relevant parts */
669 err->ekind = ekind;
670 err->addr = a;
671 err->extra = extra;
672 err->string = s;
674 /* sanity... */
675 vg_assert( tid < VG_N_THREADS );
680 /* Top-level entry point to the error management subsystem.
681 All detected errors are notified here; this routine decides if/when the
682 user should see the error. */
683 void VG_(maybe_record_error) ( ThreadId tid,
684 ErrorKind ekind, Addr a,
685 const HChar* s, void* extra )
687 Error err;
688 Error* p;
689 Error* p_prev;
690 UInt extra_size;
691 VgRes exe_res = Vg_MedRes;
692 static Bool stopping_message = False;
693 static Bool slowdown_message = False;
695 /* After M_COLLECT_NO_ERRORS_AFTER_SHOWN different errors have
696 been found, or M_COLLECT_NO_ERRORS_AFTER_FOUND total errors
697 have been found, just refuse to collect any more. This stops
698 the burden of the error-management system becoming excessive in
699 extremely buggy programs, although it does make it pretty
700 pointless to continue the Valgrind run after this point. */
701 if (VG_(clo_error_limit)
702 && (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN
703 || n_errs_found >= M_COLLECT_NO_ERRORS_AFTER_FOUND)
704 && !VG_(clo_xml)) {
705 if (!stopping_message) {
706 VG_(umsg)("\n");
708 if (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN) {
709 VG_(umsg)(
710 "More than %d different errors detected. "
711 "I'm not reporting any more.\n",
712 M_COLLECT_NO_ERRORS_AFTER_SHOWN );
713 } else {
714 VG_(umsg)(
715 "More than %d total errors detected. "
716 "I'm not reporting any more.\n",
717 M_COLLECT_NO_ERRORS_AFTER_FOUND );
720 VG_(umsg)("Final error counts will be inaccurate. "
721 "Go fix your program!\n");
722 VG_(umsg)("Rerun with --error-limit=no to disable "
723 "this cutoff. Note\n");
724 VG_(umsg)("that errors may occur in your program without "
725 "prior warning from\n");
726 VG_(umsg)("Valgrind, because errors are no longer "
727 "being displayed.\n");
728 VG_(umsg)("\n");
729 stopping_message = True;
731 return;
734 /* Ignore it if error acquisition is disabled for this thread. */
735 { ThreadState* tst = VG_(get_ThreadState)(tid);
736 if (tst->err_disablement_level > 0)
737 return;
740 /* After M_COLLECT_ERRORS_SLOWLY_AFTER different errors have
741 been found, be much more conservative about collecting new
742 ones. */
743 if (n_errs_shown >= M_COLLECT_ERRORS_SLOWLY_AFTER
744 && !VG_(clo_xml)) {
745 exe_res = Vg_LowRes;
746 if (!slowdown_message) {
747 VG_(umsg)("\n");
748 VG_(umsg)("More than %d errors detected. Subsequent errors\n",
749 M_COLLECT_ERRORS_SLOWLY_AFTER);
750 VG_(umsg)("will still be recorded, but in less "
751 "detail than before.\n");
752 slowdown_message = True;
756 /* Build ourselves the error */
757 construct_error ( &err, tid, ekind, a, s, extra, NULL );
759 /* First, see if we've got an error record matching this one. */
760 em_errlist_searches++;
761 p = errors;
762 p_prev = NULL;
763 while (p != NULL) {
764 em_errlist_cmps++;
765 if (eq_Error(exe_res, p, &err)) {
766 /* Found it. */
767 p->count++;
768 if (p->supp != NULL) {
769 /* Deal correctly with suppressed errors. */
770 p->supp->count++;
771 n_errs_suppressed++;
772 } else {
773 n_errs_found++;
776 /* Move p to the front of the list so that future searches
777 for it are faster. It also allows to print the last
778 error (see VG_(show_last_error). */
779 if (p_prev != NULL) {
780 vg_assert(p_prev->next == p);
781 p_prev->next = p->next;
782 p->next = errors;
783 errors = p;
786 return;
788 p_prev = p;
789 p = p->next;
792 /* Didn't see it. Copy and add. */
794 /* OK, we're really going to collect it. The context is on the stack and
795 will disappear shortly, so we must copy it. First do the main
796 (non-'extra') part.
798 Then VG_(tdict).tool_update_extra can update the 'extra' part. This
799 is for when there are more details to fill in which take time to work
800 out but don't affect our earlier decision to include the error -- by
801 postponing those details until now, we avoid the extra work in the
802 case where we ignore the error. Ugly.
804 Then, if there is an 'extra' part, copy it too, using the size that
805 VG_(tdict).tool_update_extra returned. Also allow for people using
806 the void* extra field for a scalar value like an integer.
809 /* copy main part */
810 p = VG_(malloc)("errormgr.mre.1", sizeof(Error));
811 *p = err;
813 /* update 'extra' */
814 switch (ekind) {
815 //(example code, see comment on CoreSuppKind above)
816 //case ThreadErr:
817 // vg_assert(VG_(needs).core_errors);
818 // extra_size = <something>
819 // break;
820 default:
821 vg_assert(VG_(needs).tool_errors);
822 extra_size = VG_TDICT_CALL(tool_update_extra, p);
823 break;
826 /* copy the error string, if there is one.
827 note: if we would have many errors with big strings, using a
828 DedupPoolAlloc for these strings will avoid duplicating
829 such string in each error using it. */
830 if (NULL != p->string) {
831 p->string = VG_(strdup)("errormgr.mre.2", p->string);
834 /* copy block pointed to by 'extra', if there is one */
835 if (NULL != p->extra && 0 != extra_size) {
836 void* new_extra = VG_(malloc)("errormgr.mre.3", extra_size);
837 VG_(memcpy)(new_extra, p->extra, extra_size);
838 p->extra = new_extra;
841 p->next = errors;
842 p->supp = is_suppressible_error(&err);
843 errors = p;
844 if (p->supp == NULL) {
845 /* update stats */
846 n_err_contexts++;
847 n_errs_found++;
848 n_errs_shown++;
849 /* Actually show the error; more complex than you might think. */
850 pp_Error( p, /*allow_db_attach*/True, VG_(clo_xml) );
851 } else {
852 n_supp_contexts++;
853 n_errs_suppressed++;
854 p->supp->count++;
858 /* Second top-level entry point to the error management subsystem, for
859 errors that the tool wants to report immediately, eg. because they're
860 guaranteed to only happen once. This avoids all the recording and
861 comparing stuff. But they can be suppressed; returns True if it is
862 suppressed. Bool 'print_error' dictates whether to print the error.
863 Bool 'count_error' dictates whether to count the error in n_errs_found.
865 Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind, Addr a, const HChar* s,
866 void* extra, ExeContext* where, Bool print_error,
867 Bool allow_db_attach, Bool count_error )
869 Error err;
870 Supp *su;
872 /* Ignore it if error acquisition is disabled for this thread. */
873 ThreadState* tst = VG_(get_ThreadState)(tid);
874 if (tst->err_disablement_level > 0)
875 return False; /* ignored, not suppressed */
877 /* Build ourselves the error */
878 construct_error ( &err, tid, ekind, a, s, extra, where );
880 /* Unless it's suppressed, we're going to show it. Don't need to make
881 a copy, because it's only temporary anyway.
883 Then update the 'extra' part with VG_(tdict).tool_update_extra),
884 because that can have an affect on whether it's suppressed. Ignore
885 the size return value of VG_(tdict).tool_update_extra, because we're
886 not copying 'extra'. Similarly, 's' is also not copied. */
887 (void)VG_TDICT_CALL(tool_update_extra, &err);
889 su = is_suppressible_error(&err);
890 if (NULL == su) {
891 if (count_error) {
892 n_errs_found++;
893 n_err_contexts++;
896 if (print_error) {
897 /* update stats */
898 n_errs_shown++;
899 /* Actually show the error; more complex than you might think. */
900 pp_Error(&err, allow_db_attach, VG_(clo_xml));
902 return False;
904 } else {
905 if (count_error) {
906 n_errs_suppressed++;
907 n_supp_contexts++;
909 su->count++;
910 return True;
915 /*------------------------------------------------------------*/
916 /*--- Exported fns ---*/
917 /*------------------------------------------------------------*/
919 /* Show the used suppressions. Returns False if no suppression
920 got used. */
921 static Bool show_used_suppressions ( void )
923 Supp *su;
924 Bool any_supp;
926 if (VG_(clo_xml))
927 VG_(printf_xml)("<suppcounts>\n");
929 any_supp = False;
930 for (su = suppressions; su != NULL; su = su->next) {
931 if (su->count <= 0)
932 continue;
933 if (VG_(clo_xml)) {
934 VG_(printf_xml)( " <pair>\n"
935 " <count>%d</count>\n"
936 " <name>%pS</name>\n"
937 " </pair>\n",
938 su->count, su->sname );
939 } else {
940 HChar *xtra = NULL;
941 Int xtra_size = 0;
942 SizeT num_written;
943 // blank line before the first shown suppression, if any
944 if (!any_supp)
945 VG_(dmsg)("\n");
947 do {
948 xtra_size += 256;
949 xtra = VG_(realloc)("errormgr.sus.1", xtra, xtra_size);
950 num_written = VG_TDICT_CALL(tool_print_extra_suppression_use,
951 su, xtra, xtra_size);
952 } while (num_written == xtra_size); // resize buffer and retry
954 // Ensure buffer is properly terminated
955 vg_assert(xtra[num_written] == '\0');
957 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
958 su->clo_suppressions_i);
959 VG_(dmsg)("used_suppression: %6d %s %s:%d%s%s\n", su->count, su->sname,
960 filename,
961 su->sname_lineno,
962 num_written ? " " : "", xtra);
963 VG_(free)(xtra);
965 any_supp = True;
968 if (VG_(clo_xml))
969 VG_(printf_xml)("</suppcounts>\n");
971 return any_supp;
974 /* Show all the errors that occurred, and possibly also the
975 suppressions used. */
976 void VG_(show_all_errors) ( Int verbosity, Bool xml )
978 Int i, n_min;
979 Error *p, *p_min;
980 Bool any_supp;
981 Bool any_error = False;
983 if (verbosity == 0 && !VG_(clo_show_error_list))
984 return;
986 /* If we're printing XML, just show the suppressions and stop. */
987 if (xml) {
988 if (VG_(clo_show_error_list))
989 (void)show_used_suppressions();
990 return;
993 /* We only get here if not printing XML. */
994 VG_(umsg)("ERROR SUMMARY: "
995 "%u errors from %u contexts (suppressed: %u from %u)\n",
996 n_errs_found, n_err_contexts,
997 n_errs_suppressed, n_supp_contexts );
999 if (!VG_(clo_show_error_list))
1000 return;
1002 // We do the following if VG_(clo_show_error_list)
1003 // or at -v or above, and only in non-XML mode.
1005 /* Print the contexts in order of increasing error count.
1006 Once an error is shown, we add a huge value to its count to filter it
1007 out.
1008 After having shown all errors, we reset count to the original value. */
1009 for (i = 0; i < n_err_contexts; i++) {
1010 n_min = (1 << 30) - 1;
1011 p_min = NULL;
1012 for (p = errors; p != NULL; p = p->next) {
1013 if (p->supp != NULL) continue;
1014 if (p->count < n_min) {
1015 n_min = p->count;
1016 p_min = p;
1019 // XXX: this isn't right. See bug 203651.
1020 if (p_min == NULL) continue; //VG_(core_panic)("show_all_errors()");
1022 any_error = True;
1023 VG_(umsg)("\n");
1024 VG_(umsg)("%d errors in context %d of %u:\n",
1025 p_min->count, i+1, n_err_contexts);
1026 pp_Error( p_min, False/*allow_db_attach*/, False /* xml */ );
1028 // We're not printing XML -- we'd have exited above if so.
1029 vg_assert(! xml);
1031 if ((i+1 == VG_(clo_dump_error))) {
1032 StackTrace ips = VG_(get_ExeContext_StackTrace)(p_min->where);
1033 VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to debugging*/,
1034 ips[0], /*debugging*/True, 0xFE/*verbosity*/,
1035 /*bbs_done*/0,
1036 /*allow redir?*/True);
1039 p_min->count = p_min->count + (1 << 30);
1042 /* reset the counts, otherwise a 2nd call does not show anything anymore */
1043 for (p = errors; p != NULL; p = p->next) {
1044 if (p->count >= (1 << 30))
1045 p->count = p->count - (1 << 30);
1049 any_supp = show_used_suppressions();
1051 if (any_supp)
1052 VG_(umsg)("\n");
1053 // reprint summary, so users don't have to scroll way up to find
1054 // the first printing
1055 if (any_supp || any_error)
1056 VG_(umsg)("ERROR SUMMARY: "
1057 "%u errors from %u contexts (suppressed: %u from %u)\n",
1058 n_errs_found, n_err_contexts, n_errs_suppressed,
1059 n_supp_contexts );
1062 void VG_(show_last_error) ( void )
1064 if (n_err_contexts == 0) {
1065 VG_(umsg)("No errors yet\n");
1066 return;
1069 pp_Error( errors, False/*allow_db_attach*/, False/*xml*/ );
1073 /* Show occurrence counts of all errors, in XML form. */
1074 void VG_(show_error_counts_as_XML) ( void )
1076 Error* err;
1077 VG_(printf_xml)("<errorcounts>\n");
1078 for (err = errors; err != NULL; err = err->next) {
1079 if (err->supp != NULL)
1080 continue;
1081 if (err->count <= 0)
1082 continue;
1083 VG_(printf_xml)(" <pair>\n");
1084 VG_(printf_xml)(" <count>%d</count>\n", err->count);
1085 VG_(printf_xml)(" <unique>0x%x</unique>\n", err->unique);
1086 VG_(printf_xml)(" </pair>\n");
1088 VG_(printf_xml)("</errorcounts>\n");
1089 VG_(printf_xml)("\n");
1093 /*------------------------------------------------------------*/
1094 /*--- Suppression parsing ---*/
1095 /*------------------------------------------------------------*/
1097 /* Get the next char from fd into *out_buf. Returns 1 if success,
1098 0 if eof or < 0 if error. */
1100 static Int get_char ( Int fd, HChar* out_buf )
1102 Int r;
1103 static HChar buf[256];
1104 static Int buf_size = 0;
1105 static Int buf_used = 0;
1106 vg_assert(buf_size >= 0 && buf_size <= sizeof buf);
1107 vg_assert(buf_used >= 0 && buf_used <= buf_size);
1108 if (buf_used == buf_size) {
1109 r = VG_(read)(fd, buf, sizeof buf);
1110 if (r < 0) return r; /* read failed */
1111 vg_assert(r >= 0 && r <= sizeof buf);
1112 buf_size = r;
1113 buf_used = 0;
1115 if (buf_size == 0)
1116 return 0; /* eof */
1117 vg_assert(buf_size >= 0 && buf_size <= sizeof buf);
1118 vg_assert(buf_used >= 0 && buf_used < buf_size);
1119 *out_buf = buf[buf_used];
1120 buf_used++;
1121 return 1;
1124 // Get a non blank non comment line.
1125 // Returns True if eof.
1126 static Bool get_nbnc_line ( Int fd, HChar** bufpp, SizeT* nBufp, Int* lineno )
1128 HChar* buf = *bufpp;
1129 SizeT nBuf = *nBufp;
1130 HChar ch;
1131 Int n, i;
1133 vg_assert(lineno); // lineno needed to correctly track line numbers.
1135 while (True) {
1136 buf[0] = 0;
1137 /* First, read until a non-blank char appears. */
1138 while (True) {
1139 n = get_char(fd, &ch);
1140 if (n == 1 && !VG_(isspace)(ch)) break;
1141 if (n == 1 && ch == '\n')
1142 (*lineno)++;
1143 if (n <= 0) return True;
1146 /* Now, read the line into buf. */
1147 i = 0;
1148 buf[i++] = ch; buf[i] = 0;
1149 while (True) {
1150 n = get_char(fd, &ch);
1151 if (n <= 0) return False; /* the next call will return True */
1152 if (ch == '\n')
1153 (*lineno)++;
1154 if (ch == '\n') break;
1155 if (i > 0 && i == nBuf-1) {
1156 *nBufp = nBuf = nBuf * 2;
1157 #define RIDICULOUS 100000
1158 vg_assert2(nBuf < RIDICULOUS, // Just a sanity check, really.
1159 "VG_(get_line): line longer than %d chars, aborting\n",
1160 RIDICULOUS);
1161 *bufpp = buf = VG_(realloc)("errormgr.get_line.1", buf, nBuf);
1163 buf[i++] = ch; buf[i] = 0;
1165 while (i > 1 && VG_(isspace)(buf[i-1])) {
1166 i--; buf[i] = 0;
1169 // VG_(printf)("The line *%p %d is '%s'\n", lineno, *lineno, buf);
1170 /* Ok, we have a line. If a non-comment line, return.
1171 If a comment line, start all over again. */
1172 if (buf[0] != '#') return False;
1176 // True if buf starts with fun: or obj: or is ...
1177 static Bool is_location_line (const HChar* buf)
1179 return VG_(strncmp)(buf, "fun:", 4) == 0
1180 || VG_(strncmp)(buf, "obj:", 4) == 0
1181 || VG_(strcmp)(buf, "...") == 0;
1184 Bool VG_(get_line) ( Int fd, HChar** bufpp, SizeT* nBufp, Int* lineno )
1186 Bool eof = get_nbnc_line (fd, bufpp, nBufp, lineno);
1188 if (eof)
1189 return True;
1191 if (is_location_line(*bufpp))
1192 return True; // Not a extra suppr line
1193 else
1194 return False; // A suppression extra line
1197 /* True if s contains no wildcard (?, *) characters. */
1198 static Bool is_simple_str (const HChar *s)
1200 while (*s) {
1201 if (*s == '?' || *s == '*')
1202 return False;
1203 s++;
1205 return True;
1208 /* buf contains the raw name of a caller, supposedly either
1209 fun:some_function_name or
1210 obj:some_object_name or
1211 src:some_file_name or
1212 src:some_file_name:line# or
1214 Set p->ty and p->name accordingly.
1215 p->name is allocated and set to the string
1216 after the descriptor (fun:, obj:, or src: san line#) part.
1217 p->lineno is set to non-zero if line# specified; 0 otherwise.
1218 Returns False if failed.
1220 static Bool setLocationTy ( SuppLoc* p, const HChar *buf )
1222 if (VG_(strncmp)(buf, "fun:", 4) == 0) {
1223 p->name = VG_(strdup)("errormgr.sLTy.1", buf+4);
1224 p->name_is_simple_str = is_simple_str (p->name);
1225 p->ty = FunName;
1226 return True;
1228 if (VG_(strncmp)(buf, "obj:", 4) == 0) {
1229 p->name = VG_(strdup)("errormgr.sLTy.2", buf+4);
1230 p->name_is_simple_str = is_simple_str (p->name);
1231 p->ty = ObjName;
1232 return True;
1234 if (VG_(strncmp)(buf, "src:", 4) == 0) {
1235 p->name = VG_(strdup)("errormgr.sLTy.3", buf+4);
1236 p->name_is_simple_str = is_simple_str (p->name);
1237 p->ty = SrcName;
1238 HChar *s = VG_(strchr)(p->name, ':');
1239 if (s != NULL) {
1240 *s++ = '\0'; // trim colon
1241 p->lineno = (UInt) VG_(strtoll10)(s, NULL);
1242 } else {
1243 p->lineno = 0;
1245 return True;
1247 if (VG_(strcmp)(buf, "...") == 0) {
1248 p->name = NULL;
1249 p->name_is_simple_str = False;
1250 p->ty = DotDotDot;
1251 return True;
1253 VG_(printf)("location should be \"...\", or should start "
1254 "with \"fun:\", \"obj:\", or \"src:\"\n");
1255 return False;
1259 /* Look for "tool" in a string like "tool1,tool2,tool3" */
1260 static Bool tool_name_present(const HChar *name, const HChar *names)
1262 Bool found;
1263 HChar *s = NULL; /* Shut gcc up */
1264 Int len = VG_(strlen)(name);
1266 found = (NULL != (s = VG_(strstr)(names, name))
1267 && (s == names || *(s-1) == ',')
1268 && (*(s+len) == ',' || *(s+len) == '\0'));
1270 return found;
1273 /* Read suppressions from the file specified in
1274 VG_(clo_suppressions)[clo_suppressions_i]
1275 and place them in the suppressions list. If there's any difficulty
1276 doing this, just give up -- there's no point in trying to recover.
1278 static void load_one_suppressions_file ( Int clo_suppressions_i )
1280 const HChar* filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1281 clo_suppressions_i);
1282 SysRes sres;
1283 Int fd, i, j, lineno = 0;
1284 Bool got_a_location_line_read_by_tool;
1285 Bool eof;
1286 SizeT nBuf = 200;
1287 HChar* buf = VG_(malloc)("errormgr.losf.1", nBuf);
1288 HChar* tool_names;
1289 HChar* supp_name;
1290 const HChar* err_str = NULL;
1291 SuppLoc tmp_callers[VG_DEEPEST_BACKTRACE];
1293 // Check it's not a directory.
1294 if (VG_(is_dir)( filename )) {
1295 if (VG_(clo_xml))
1296 VG_(printf_xml)("</valgrindoutput>\n");
1297 VG_(umsg)("FATAL: suppressions file \"%s\" is a directory\n", filename );
1298 VG_(exit)(1);
1301 // Open the suppression file.
1302 sres = VG_(open)( filename, VKI_O_RDONLY, 0 );
1303 if (sr_isError(sres)) {
1304 if (VG_(clo_xml))
1305 VG_(printf_xml)("</valgrindoutput>\n");
1306 VG_(umsg)("FATAL: can't open suppressions file \"%s\"\n", filename );
1307 VG_(exit)(1);
1309 fd = sr_Res(sres);
1311 # define BOMB(S) { err_str = S; goto syntax_error; }
1313 while (True) {
1314 /* Assign and initialise the two suppression halves (core and tool) */
1315 Supp* supp;
1316 supp = VG_(malloc)("errormgr.losf.1", sizeof(Supp));
1317 supp->count = 0;
1319 // Initialise temporary reading-in buffer.
1320 for (i = 0; i < VG_DEEPEST_BACKTRACE; i++) {
1321 tmp_callers[i].ty = NoName;
1322 tmp_callers[i].name_is_simple_str = False;
1323 tmp_callers[i].name = NULL;
1326 supp->string = supp->extra = NULL;
1328 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1329 if (eof) {
1330 VG_(free)(supp);
1331 break;
1334 if (!VG_STREQ(buf, "{")) BOMB("expected '{' or end-of-file");
1336 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1338 if (eof || VG_STREQ(buf, "}")) BOMB("unexpected '}'");
1340 supp->sname = VG_(strdup)("errormgr.losf.2", buf);
1341 supp->clo_suppressions_i = clo_suppressions_i;
1342 supp->sname_lineno = lineno;
1344 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1346 if (eof) BOMB("unexpected end-of-file (expecting tool:suppr)");
1348 /* Check it has the "tool1,tool2,...:supp" form (look for ':') */
1349 i = 0;
1350 while (True) {
1351 if (buf[i] == ':') break;
1352 if (buf[i] == '\0') BOMB("malformed 'tool1,tool2,...:supp' line");
1353 i++;
1355 buf[i] = '\0'; /* Replace ':', splitting into two strings */
1357 tool_names = & buf[0];
1358 supp_name = & buf[i+1];
1360 if (VG_(needs).core_errors && tool_name_present("core", tool_names)) {
1361 // A core suppression
1362 //(example code, see comment on CoreSuppKind above)
1363 //if (VG_STREQ(supp_name, "Thread"))
1364 // supp->skind = ThreadSupp;
1365 //else
1366 BOMB("unknown core suppression type");
1368 else if (VG_(needs).tool_errors
1369 && tool_name_present(VG_(details).name, tool_names)) {
1370 // A tool suppression
1371 if (VG_TDICT_CALL(tool_recognised_suppression, supp_name, supp)) {
1372 /* Do nothing, function fills in supp->skind */
1373 } else {
1374 BOMB("unknown tool suppression type");
1377 else {
1378 // Ignore rest of suppression
1379 while (True) {
1380 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1381 if (eof) BOMB("unexpected end-of-file (when skipping suppression)");
1382 if (VG_STREQ(buf, "}"))
1383 break;
1385 VG_(free)(supp->sname);
1386 VG_(free)(supp);
1387 continue;
1390 buf[0] = 0;
1391 // tool_read_extra_suppression_info might read lines
1392 // from fd till a location line.
1393 if (VG_(needs).tool_errors
1394 && !VG_TDICT_CALL(tool_read_extra_suppression_info,
1395 fd, &buf, &nBuf, &lineno, supp)) {
1396 BOMB("bad or missing extra suppression info");
1399 got_a_location_line_read_by_tool = buf[0] != 0 && is_location_line(buf);
1401 /* the main frame-descriptor reading loop */
1402 i = 0;
1403 while (True) {
1404 if (got_a_location_line_read_by_tool) {
1405 got_a_location_line_read_by_tool = False;
1406 eof = False;
1407 } else {
1408 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1410 if (eof)
1411 BOMB("unexpected end-of-file (when reading stack trace)");
1412 if (VG_STREQ(buf, "}")) {
1413 if (i > 0) {
1414 break;
1415 } else {
1416 BOMB("missing stack trace");
1419 if (i == VG_DEEPEST_BACKTRACE)
1420 BOMB("too many callers in stack trace");
1421 if (i > 0 && i >= VG_(clo_backtrace_size))
1422 break;
1423 if (!setLocationTy(&(tmp_callers[i]), buf))
1424 BOMB("location should be \"...\", or should start "
1425 "with \"fun:\", \"obj:\", or \"src:\"");
1426 i++;
1429 // If the num callers is >= VG_(clo_backtrace_size), ignore any extra
1430 // lines and grab the '}'.
1431 if (!VG_STREQ(buf, "}")) {
1432 do {
1433 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1434 } while (!eof && !VG_STREQ(buf, "}"));
1437 // Reject entries which are entirely composed of frame
1438 // level wildcards.
1439 vg_assert(i > 0); // guaranteed by frame-descriptor reading loop
1440 for (j = 0; j < i; j++) {
1441 if (tmp_callers[j].ty == FunName || tmp_callers[j].ty == ObjName
1442 || tmp_callers[j].ty == SrcName) {
1443 break;
1445 vg_assert(tmp_callers[j].ty == DotDotDot);
1447 vg_assert(j >= 0 && j <= i);
1448 if (j == i) {
1449 // we didn't find any non-"..." entries
1450 BOMB("suppression must contain at least one location "
1451 "line which is not \"...\"");
1454 // Copy tmp_callers[] into supp->callers[]
1455 supp->n_callers = i;
1456 supp->callers = VG_(malloc)("errormgr.losf.4", i * sizeof(SuppLoc));
1457 for (i = 0; i < supp->n_callers; i++) {
1458 supp->callers[i] = tmp_callers[i];
1461 supp->next = suppressions;
1462 suppressions = supp;
1464 VG_(free)(buf);
1465 VG_(close)(fd);
1466 return;
1468 syntax_error:
1469 if (VG_(clo_xml))
1470 VG_(printf_xml)("</valgrindoutput>\n");
1471 VG_(umsg)("FATAL: in suppressions file \"%s\" near line %d:\n",
1472 filename, lineno );
1473 VG_(umsg)(" %s\n", err_str );
1475 VG_(close)(fd);
1476 VG_(umsg)("exiting now.\n");
1477 VG_(exit)(1);
1479 # undef BOMB
1482 void VG_(add_suppression_file)(const HChar *filename)
1484 HChar *f = VG_(strdup)("errormgr.addsup", filename);
1485 VG_(addToXA)(VG_(clo_suppressions), &f);
1486 if (load_suppressions_called)
1487 load_one_suppressions_file( VG_(sizeXA)(VG_(clo_suppressions)) - 1 );
1490 void VG_(load_suppressions) ( void )
1492 Int i;
1493 suppressions = NULL;
1494 load_suppressions_called = True;
1495 for (i = 0; i < VG_(sizeXA)(VG_(clo_suppressions)); i++) {
1496 if (VG_(clo_verbosity) > 1) {
1497 VG_(dmsg)("Reading suppressions file: %s\n",
1498 *(HChar**) VG_(indexXA)(VG_(clo_suppressions), i));
1500 load_one_suppressions_file( i );
1505 /*------------------------------------------------------------*/
1506 /*--- Matching errors to suppressions ---*/
1507 /*------------------------------------------------------------*/
1509 /* Parameterising functions for the use of VG_(generic_match) in
1510 suppression-vs-error matching. The suppression frames (SuppLoc)
1511 play the role of 'pattern'-element, and the error frames (IPs,
1512 hence simply Addrs) play the role of 'input'. In short then, we're
1513 matching a sequence of Addrs against a pattern composed of a
1514 sequence of SuppLocs.
1516 static Bool supploc_IsStar ( const void* supplocV )
1518 const SuppLoc* supploc = supplocV;
1519 return supploc->ty == DotDotDot;
1522 static Bool supploc_IsQuery ( const void* supplocV )
1524 return False; /* there's no '?' equivalent in the supp syntax */
1527 /* IPtoFunOrObjCompleter is a lazy completer of the IPs
1528 needed to match an error with the suppression patterns.
1529 The matching between an IP and a suppression pattern is done either
1530 with the IP function name or with the IP object name.
1531 First time the fun or obj name is needed for an IP member
1532 of a stack trace, it will be computed and stored in names.
1533 Also, if the IP corresponds to one or more inlined function calls,
1534 the inlined function names are expanded.
1535 The IPtoFunOrObjCompleter type is designed to minimise the nr of
1536 allocations and the nr of debuginfo search. */
1537 typedef
1538 struct {
1539 DiEpoch epoch; // used to interpret .ips
1540 StackTrace ips; // stack trace we are lazily completing.
1541 UWord n_ips; // nr of elements in ips.
1543 // VG_(generic_match) calls haveInputInpC to check
1544 // for the presence of an input element identified by ixInput
1545 // (i.e. a number that identifies the ixInput element of the
1546 // input sequence). It calls supp_pattEQinp to match this input
1547 // element with a pattern.
1548 // When inlining info is used to provide inlined function calls
1549 // in stacktraces, one IP in ips can be expanded in several
1550 // function names. So, each time input (or presence of input)
1551 // is requested by VG_(generic_match), we will expand
1552 // more IP of ips till we have expanded enough to reach the
1553 // input element requested (or we cannot expand anymore).
1555 UWord n_ips_expanded;
1556 // n_ips_expanded maintains the nr of elements in ips that we have
1557 // already expanded.
1558 UWord n_expanded;
1559 // n_expanded maintains the nr of elements resulting from the expansion
1560 // of the n_ips_expanded IPs. Without inlined function calls,
1561 // n_expanded == n_ips_expanded. With inlining info,
1562 // n_expanded >= n_ips_expanded.
1564 Int* n_offsets_per_ip;
1565 // n_offsets_per_ip[i] gives the nr of offsets in fun_offsets and
1566 // obj_offsets resulting of the expansion of ips[i].
1567 // The sum of all n_expanded_per_ip must be equal to n_expanded.
1568 // This array allows to retrieve the position in ips corresponding to
1569 // an ixInput.
1571 // size (in elements) of fun_offsets and obj_offsets.
1572 // (fun|obj)_offsets are reallocated if more space is needed
1573 // to expand an IP.
1574 UWord sz_offsets;
1576 Int* fun_offsets;
1577 // fun_offsets[ixInput] is the offset in names where the
1578 // function name for the ixInput element of the input sequence
1579 // can be found. As one IP of ips can be expanded in several
1580 // function calls due to inlined function calls, we can have more
1581 // elements in fun_offsets than in ips.
1582 // An offset -1 means the function name has not yet been computed.
1583 Int* obj_offsets;
1584 // Similarly, obj_offsets[ixInput] gives the offset for the
1585 // object name for ips[ixInput]
1586 // (-1 meaning object name not yet been computed).
1588 // All function names and object names will be concatenated
1589 // in names. names is reallocated on demand.
1590 HChar *names;
1591 Int names_szB; // size of names.
1592 Int names_free; // offset first free HChar in names.
1594 IPtoFunOrObjCompleter;
1596 static void pp_ip2fo (const IPtoFunOrObjCompleter* ip2fo)
1598 Int i, j;
1599 Int o;
1601 VG_(printf)("n_ips %lu n_ips_expanded %lu resulting in n_expanded %lu\n",
1602 ip2fo->n_ips, ip2fo->n_ips_expanded, ip2fo->n_expanded);
1603 for (i = 0; i < ip2fo->n_ips_expanded; i++) {
1604 o = 0;
1605 for (j = 0; j < i; j++)
1606 o += ip2fo->n_offsets_per_ip[j];
1607 VG_(printf)("ips %d 0x08%lx offset [%d,%d] ",
1608 i, ip2fo->ips[i],
1609 o, o+ip2fo->n_offsets_per_ip[i]-1);
1610 for (j = 0; j < ip2fo->n_offsets_per_ip[i]; j++) {
1611 VG_(printf)("%sfun:%s obj:%s\n",
1612 j == 0 ? "" : " ",
1613 ip2fo->fun_offsets[o+j] == -1 ?
1614 "<not expanded>" : &ip2fo->names[ip2fo->fun_offsets[o+j]],
1615 ip2fo->obj_offsets[o+j] == -1 ?
1616 "<not expanded>" : &ip2fo->names[ip2fo->obj_offsets[o+j]]);
1621 /* free the memory in ip2fo.
1622 At debuglog 4, su (or NULL) will be used to show the matching
1623 (or non matching) with ip2fo. */
1624 static void clearIPtoFunOrObjCompleter ( const Supp *su,
1625 IPtoFunOrObjCompleter* ip2fo)
1627 if (DEBUG_ERRORMGR || VG_(debugLog_getLevel)() >= 4) {
1628 if (su) {
1629 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1630 su->clo_suppressions_i);
1631 VG_(dmsg)("errormgr matching end suppression %s %s:%d matched:\n",
1632 su->sname,
1633 filename,
1634 su->sname_lineno);
1635 } else {
1636 VG_(dmsg)("errormgr matching end no suppression matched:\n");
1638 VG_(pp_StackTrace) (ip2fo->epoch, ip2fo->ips, ip2fo->n_ips);
1639 pp_ip2fo(ip2fo);
1641 if (ip2fo->n_offsets_per_ip) VG_(free)(ip2fo->n_offsets_per_ip);
1642 if (ip2fo->fun_offsets) VG_(free)(ip2fo->fun_offsets);
1643 if (ip2fo->obj_offsets) VG_(free)(ip2fo->obj_offsets);
1644 if (ip2fo->names) VG_(free)(ip2fo->names);
1647 /* Grow ip2fo->names to ensure we have NEEDED characters available
1648 in ip2fo->names and returns a pointer to the first free char. */
1649 static HChar* grow_names(IPtoFunOrObjCompleter* ip2fo, SizeT needed)
1651 if (ip2fo->names_szB
1652 < ip2fo->names_free + needed) {
1653 if (needed < ERRTXT_LEN) needed = ERRTXT_LEN;
1655 ip2fo->names
1656 = VG_(realloc)("foc_names",
1657 ip2fo->names,
1658 ip2fo->names_szB + needed);
1659 ip2fo->names_szB += needed;
1661 return ip2fo->names + ip2fo->names_free;
1664 /* foComplete returns the function name or object name for ixInput.
1665 If needFun, returns the function name for this input
1666 else returns the object name for this input.
1667 The function name or object name will be computed and added in
1668 names if not yet done. */
1669 static HChar* foComplete(IPtoFunOrObjCompleter* ip2fo,
1670 Int ixInput, Bool needFun)
1672 vg_assert (ixInput < ip2fo->n_expanded);
1673 vg_assert (VG_(clo_read_inline_info) || ixInput < ip2fo->n_ips);
1675 // ptr to the offset array for function offsets (if needFun)
1676 // or object offsets (if !needFun).
1677 Int** offsets;
1678 if (needFun)
1679 offsets = &ip2fo->fun_offsets;
1680 else
1681 offsets = &ip2fo->obj_offsets;
1683 // Complete Fun name or Obj name for IP if not yet done.
1684 if ((*offsets)[ixInput] == -1) {
1685 const HChar* caller;
1687 (*offsets)[ixInput] = ip2fo->names_free;
1688 if (DEBUG_ERRORMGR) VG_(printf)("marking %s ixInput %d offset %d\n",
1689 needFun ? "fun" : "obj",
1690 ixInput, ip2fo->names_free);
1691 if (needFun) {
1692 // With inline info, fn names must have been completed already.
1693 vg_assert (!VG_(clo_read_inline_info));
1694 /* Get the function name into 'caller_name', or "???"
1695 if unknown. */
1696 // Nb: C++-mangled names are used in suppressions. Do, though,
1697 // Z-demangle them, since otherwise it's possible to wind
1698 // up comparing "malloc" in the suppression against
1699 // "_vgrZU_libcZdsoZa_malloc" in the backtrace, and the
1700 // two of them need to be made to match.
1701 if (!VG_(get_fnname_no_cxx_demangle)(ip2fo->epoch,
1702 ip2fo->ips[ixInput],
1703 &caller,
1704 NULL))
1705 caller = "???";
1706 } else {
1707 /* Get the object name into 'caller_name', or "???"
1708 if unknown. */
1709 UWord i;
1710 UWord last_expand_pos_ips = 0;
1711 UWord pos_ips;
1713 /* First get the pos in ips corresponding to ixInput */
1714 for (pos_ips = 0; pos_ips < ip2fo->n_expanded; pos_ips++) {
1715 last_expand_pos_ips += ip2fo->n_offsets_per_ip[pos_ips];
1716 if (ixInput < last_expand_pos_ips)
1717 break;
1719 /* pos_ips is the position in ips corresponding to ixInput.
1720 last_expand_pos_ips is the last offset in fun/obj where
1721 ips[pos_ips] has been expanded. */
1723 if (!VG_(get_objname)(ip2fo->epoch, ip2fo->ips[pos_ips], &caller))
1724 caller = "???";
1726 // Have all inlined calls pointing at this object name
1727 for (i = last_expand_pos_ips - ip2fo->n_offsets_per_ip[pos_ips] + 1;
1728 i < last_expand_pos_ips;
1729 i++) {
1730 ip2fo->obj_offsets[i] = ip2fo->names_free;
1731 if (DEBUG_ERRORMGR)
1732 VG_(printf) (" set obj_offset %lu to %d\n",
1733 i, ip2fo->names_free);
1736 SizeT caller_len = VG_(strlen)(caller);
1737 HChar* caller_name = grow_names(ip2fo, caller_len + 1);
1738 VG_(strcpy)(caller_name, caller);
1739 ip2fo->names_free += caller_len + 1;
1740 if (DEBUG_ERRORMGR) pp_ip2fo(ip2fo);
1743 return ip2fo->names + (*offsets)[ixInput];
1746 // Grow fun and obj _offsets arrays to have at least n_req elements.
1747 // Ensure n_offsets_per_ip is allocated.
1748 static void grow_offsets(IPtoFunOrObjCompleter* ip2fo, Int n_req)
1750 Int i;
1752 // n_offsets_per_ip must always have the size of the ips array
1753 if (ip2fo->n_offsets_per_ip == NULL) {
1754 ip2fo->n_offsets_per_ip = VG_(malloc)("grow_offsets",
1755 ip2fo->n_ips * sizeof(Int));
1756 for (i = 0; i < ip2fo->n_ips; i++)
1757 ip2fo->n_offsets_per_ip[i] = 0;
1760 if (ip2fo->sz_offsets >= n_req)
1761 return;
1763 // Avoid too much re-allocation by allocating at least ip2fo->n_ips
1764 // elements and at least a few more elements than the current size.
1765 if (n_req < ip2fo->n_ips)
1766 n_req = ip2fo->n_ips;
1767 if (n_req < ip2fo->sz_offsets + 5)
1768 n_req = ip2fo->sz_offsets + 5;
1770 ip2fo->fun_offsets = VG_(realloc)("grow_offsets", ip2fo->fun_offsets,
1771 n_req * sizeof(Int));
1772 for (i = ip2fo->sz_offsets; i < n_req; i++)
1773 ip2fo->fun_offsets[i] = -1;
1775 ip2fo->obj_offsets = VG_(realloc)("grow_offsets", ip2fo->obj_offsets,
1776 n_req * sizeof(Int));
1777 for (i = ip2fo->sz_offsets; i < n_req; i++)
1778 ip2fo->obj_offsets[i] = -1;
1780 ip2fo->sz_offsets = n_req;
1783 // Expands more IPs from ip2fo->ips.
1784 static void expandInput (IPtoFunOrObjCompleter* ip2fo, UWord ixInput )
1786 while (ip2fo->n_ips_expanded < ip2fo->n_ips
1787 && ip2fo->n_expanded <= ixInput) {
1788 if (VG_(clo_read_inline_info)) {
1789 // Expand one more IP in one or more calls.
1790 const Addr IP = ip2fo->ips[ip2fo->n_ips_expanded];
1791 InlIPCursor *iipc;
1793 iipc = VG_(new_IIPC)(ip2fo->epoch, IP);
1794 // The only thing we really need is the nr of inlined fn calls
1795 // corresponding to the IP we will expand.
1796 // However, computing this is mostly the same as finding
1797 // the function name. So, let's directly complete the function name.
1798 do {
1799 const HChar *caller;
1800 grow_offsets(ip2fo, ip2fo->n_expanded+1);
1801 ip2fo->fun_offsets[ip2fo->n_expanded] = ip2fo->names_free;
1802 if (!VG_(get_fnname_no_cxx_demangle)(ip2fo->epoch, IP,
1803 &caller,
1804 iipc))
1805 caller = "???";
1806 SizeT caller_len = VG_(strlen)(caller);
1807 HChar* caller_name = grow_names(ip2fo, caller_len + 1);
1808 VG_(strcpy)(caller_name, caller);
1809 ip2fo->names_free += caller_len + 1;
1810 ip2fo->n_expanded++;
1811 ip2fo->n_offsets_per_ip[ip2fo->n_ips_expanded]++;
1812 } while (VG_(next_IIPC)(iipc));
1813 ip2fo->n_ips_expanded++;
1814 VG_(delete_IIPC) (iipc);
1815 } else {
1816 // Without inlined fn call info, expansion simply
1817 // consists in allocating enough elements in (fun|obj)_offsets.
1818 // The function or object names themselves will be completed
1819 // when requested.
1820 Int i;
1821 grow_offsets(ip2fo, ip2fo->n_ips);
1822 ip2fo->n_ips_expanded = ip2fo->n_ips;
1823 ip2fo->n_expanded = ip2fo->n_ips;
1824 for (i = 0; i < ip2fo->n_ips; i++)
1825 ip2fo->n_offsets_per_ip[i] = 1;
1830 static Bool haveInputInpC (void* inputCompleterV, UWord ixInput )
1832 IPtoFunOrObjCompleter* ip2fo = (IPtoFunOrObjCompleter*)inputCompleterV;
1833 expandInput(ip2fo, ixInput);
1834 return ixInput < ip2fo->n_expanded;
1837 static Bool supp_pattEQinp ( const void* supplocV, const void* addrV,
1838 void* inputCompleterV, UWord ixInput )
1840 const SuppLoc* supploc = (const SuppLoc*)supplocV; /* PATTERN */
1841 IPtoFunOrObjCompleter* ip2fo = (IPtoFunOrObjCompleter*)inputCompleterV;
1842 const HChar* funobjsrc_name; // Fun, Obj, or src file name.
1843 UInt src_lineno = 0;
1844 Bool ret;
1846 expandInput(ip2fo, ixInput);
1847 vg_assert(ixInput < ip2fo->n_expanded);
1849 /* So, does this IP address match this suppression-line? */
1850 switch (supploc->ty) {
1851 case DotDotDot:
1852 /* supp_pattEQinp is a callback from VG_(generic_match). As
1853 per the spec thereof (see include/pub_tool_seqmatch.h), we
1854 should never get called with a pattern value for which the
1855 _IsStar or _IsQuery function would return True. Hence
1856 this can't happen. */
1857 vg_assert(0);
1858 case ObjName:
1859 funobjsrc_name = foComplete(ip2fo, ixInput, False /*needFun*/);
1860 break;
1861 case FunName:
1862 funobjsrc_name = foComplete(ip2fo, ixInput, True /*needFun*/);
1863 break;
1864 case SrcName: {
1865 const HChar* src_dirname; // placeholder only
1866 ret = VG_(get_filename_linenum)(VG_(current_DiEpoch)(),
1867 ip2fo->ips[ixInput], &funobjsrc_name, &src_dirname, &src_lineno);
1868 if (!ret) {
1869 /* No file name found for location so no way this is a match. */
1870 return ret;
1872 break;
1874 default:
1875 vg_assert(0);
1878 /* So now we have the function or object name in funobjsrc_name, and
1879 the pattern (at the character level) to match against is in
1880 supploc->name. Hence (and leading to a re-entrant call of
1881 VG_(generic_match) if there is a wildcard character): */
1882 if (supploc->name_is_simple_str)
1883 ret = VG_(strcmp) (supploc->name, funobjsrc_name) == 0;
1884 else
1885 ret = VG_(string_match)(supploc->name, funobjsrc_name);
1886 if (ret && supploc->ty == SrcName && supploc->lineno != 0) {
1887 ret = (supploc->lineno == src_lineno);
1889 if (DEBUG_ERRORMGR)
1890 VG_(printf) ("supp_pattEQinp %s patt %s ixInput %lu value:%s (lineno:%u vs %u) match:%s\n",
1891 supploc->ty == FunName ? "fun" : (supploc->ty == SrcName ? "src" : "obj"),
1892 supploc->name, ixInput, funobjsrc_name,
1893 supploc->ty == SrcName ? supploc->lineno : 0,
1894 supploc->ty == SrcName ? src_lineno : 0,
1895 ret ? "yes" : "no");
1896 return ret;
1899 /////////////////////////////////////////////////////
1901 static Bool supp_matches_callers(IPtoFunOrObjCompleter* ip2fo,
1902 const Supp* su)
1904 /* Unwrap the args and set up the correct parameterisation of
1905 VG_(generic_match), using supploc_IsStar, supploc_IsQuery and
1906 supp_pattEQinp. */
1907 /* note, StackTrace ip2fo->ips === Addr* */
1908 SuppLoc* supps = su->callers;
1909 UWord n_supps = su->n_callers;
1910 UWord szbPatt = sizeof(SuppLoc);
1911 Bool matchAll = False; /* we just want to match a prefix */
1912 if (DEBUG_ERRORMGR) {
1913 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1914 su->clo_suppressions_i);
1915 VG_(dmsg)(" errormgr Checking match with %s %s:%d\n",
1916 su->sname,
1917 filename,
1918 su->sname_lineno);
1920 return
1921 VG_(generic_match)(
1922 matchAll,
1923 /*PATT*/supps, szbPatt, n_supps, 0/*initial ixPatt*/,
1924 /*INPUT*/
1925 NULL, 0, 0, /* input/szbInput/nInput 0, as using an inputCompleter */
1926 0/*initial ixInput*/,
1927 supploc_IsStar, supploc_IsQuery, supp_pattEQinp,
1928 ip2fo, haveInputInpC
1932 /////////////////////////////////////////////////////
1934 static
1935 Bool supp_matches_error(const Supp* su, const Error* err)
1937 switch (su->skind) {
1938 //(example code, see comment on CoreSuppKind above)
1939 //case ThreadSupp:
1940 // return (err->ekind == ThreadErr);
1941 default:
1942 if (VG_(needs).tool_errors) {
1943 return VG_TDICT_CALL(tool_error_matches_suppression, err, su);
1944 } else {
1945 VG_(printf)(
1946 "\nUnhandled suppression type: %u. VG_(needs).tool_errors\n"
1947 "probably needs to be set.\n",
1948 (UInt)err->ekind);
1949 VG_(core_panic)("unhandled suppression type");
1954 /////////////////////////////////////////////////////
1956 /* Does an error context match a suppression? ie is this a suppressible
1957 error? If so, return a pointer to the Supp record, otherwise NULL.
1958 Tries to minimise the number of symbol searches since they are expensive.
1960 static Supp* is_suppressible_error ( const Error* err )
1962 Supp* su;
1963 Supp* su_prev;
1965 IPtoFunOrObjCompleter ip2fo;
1966 /* Conceptually, ip2fo contains an array of function names and an array of
1967 object names, corresponding to the array of IP of err->where.
1968 These names are just computed 'on demand' (so once maximum),
1969 then stored (efficiently, avoiding too many allocs) in ip2fo to be
1970 re-usable for the matching of the same IP with the next suppression
1971 pattern.
1973 VG_(generic_match) gets this 'IP to Fun or Obj name completer' as one
1974 of its arguments. It will then pass it to the function
1975 supp_pattEQinp which will then lazily complete the IP function name or
1976 object name inside ip2fo. Next time the fun or obj name for the same
1977 IP is needed (i.e. for the matching with the next suppr pattern), then
1978 the fun or obj name will not be searched again in the debug info. */
1980 /* stats gathering */
1981 em_supplist_searches++;
1983 /* Prepare the lazy input completer. */
1984 ip2fo.epoch = VG_(get_ExeContext_epoch)(err->where);
1985 ip2fo.ips = VG_(get_ExeContext_StackTrace)(err->where);
1986 ip2fo.n_ips = VG_(get_ExeContext_n_ips)(err->where);
1987 ip2fo.n_ips_expanded = 0;
1988 ip2fo.n_expanded = 0;
1989 ip2fo.sz_offsets = 0;
1990 ip2fo.n_offsets_per_ip = NULL;
1991 ip2fo.fun_offsets = NULL;
1992 ip2fo.obj_offsets = NULL;
1993 ip2fo.names = NULL;
1994 ip2fo.names_szB = 0;
1995 ip2fo.names_free = 0;
1997 /* See if the error context matches any suppression. */
1998 if (DEBUG_ERRORMGR || VG_(debugLog_getLevel)() >= 4)
1999 VG_(dmsg)("errormgr matching begin\n");
2000 su_prev = NULL;
2001 for (su = suppressions; su != NULL; su = su->next) {
2002 em_supplist_cmps++;
2003 if (supp_matches_error(su, err)
2004 && supp_matches_callers(&ip2fo, su)) {
2005 /* got a match. */
2006 /* Inform the tool that err is suppressed by su. */
2007 (void)VG_TDICT_CALL(tool_update_extra_suppression_use, err, su);
2008 /* Move this entry to the head of the list
2009 in the hope of making future searches cheaper. */
2010 if (su_prev) {
2011 vg_assert(su_prev->next == su);
2012 su_prev->next = su->next;
2013 su->next = suppressions;
2014 suppressions = su;
2016 clearIPtoFunOrObjCompleter(su, &ip2fo);
2017 return su;
2019 su_prev = su;
2021 clearIPtoFunOrObjCompleter(NULL, &ip2fo);
2022 return NULL; /* no matches */
2025 /* Show accumulated error-list and suppression-list search stats.
2027 void VG_(print_errormgr_stats) ( void )
2029 VG_(dmsg)(
2030 " errormgr: %'lu supplist searches, %'lu comparisons during search\n",
2031 em_supplist_searches, em_supplist_cmps
2033 VG_(dmsg)(
2034 " errormgr: %'lu errlist searches, %'lu comparisons during search\n",
2035 em_errlist_searches, em_errlist_cmps
2039 /*--------------------------------------------------------------------*/
2040 /*--- end ---*/
2041 /*--------------------------------------------------------------------*/