FreeBSD: add file descriptor tracking for _umtx_op
[valgrind.git] / coregrind / m_errormgr.c
blob4984d30aba00dcd2e663abc51cc1474a47091aee
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
49 #include "pub_core_syswrap.h" // for core callbacks (Fds)
51 #define DEBUG_ERRORMGR 0 // set to 1 for heavyweight tracing
53 /*------------------------------------------------------------*/
54 /*--- Globals ---*/
55 /*------------------------------------------------------------*/
57 /* After this many different unsuppressed errors have been observed,
58 be more conservative about collecting new ones. */
59 #define M_COLLECT_ERRORS_SLOWLY_AFTER 100
61 /* After this many different unsuppressed errors have been observed,
62 stop collecting errors at all, and tell the user their program is
63 evidently a steaming pile of camel dung. */
64 #define M_COLLECT_NO_ERRORS_AFTER_SHOWN 1000
66 /* After this many total errors have been observed, stop collecting
67 errors at all. Counterpart to M_COLLECT_NO_ERRORS_AFTER_SHOWN. */
68 #define M_COLLECT_NO_ERRORS_AFTER_FOUND 10000000
70 /* The list of error contexts found, both suppressed and unsuppressed.
71 Initially empty, and grows as errors are detected. */
72 static Error* errors = NULL;
74 /* The list of suppression directives, as read from the specified
75 suppressions file. Note that the list gets rearranged as a result
76 of the searches done by is_suppressible_error(). */
77 static Supp* suppressions = NULL;
78 static Bool load_suppressions_called = False;
80 /* Running count of unsuppressed errors detected. */
81 static UInt n_errs_found = 0;
83 /* Running count of suppressed errors detected. */
84 static UInt n_errs_suppressed = 0;
86 /* Running count of errors shown. */
87 static UInt n_errs_shown = 0;
89 /* Running count of unsuppressed error contexts. */
90 static UInt n_err_contexts = 0;
92 /* Running count of suppressed error contexts. */
93 static UInt n_supp_contexts = 0;
96 /* forwards ... */
97 static Supp* is_suppressible_error ( const Error* err );
99 static Bool core_eq_Error (VgRes, const Error*, const Error*);
100 static void core_before_pp_Error (const Error*);
101 static void core_pp_Error (const Error*);
102 static UInt core_update_extra (const Error*);
104 static const HChar *core_get_error_name(const Error*);
105 static SizeT core_get_extra_suppression_info(const Error*,HChar*,Int);
107 static ThreadId last_tid_printed = 1;
109 /* Stats: number of searches of the error list initiated. */
110 static UWord em_errlist_searches = 0;
112 /* Stats: number of comparisons done during error list
113 searching. */
114 static UWord em_errlist_cmps = 0;
116 /* Stats: number of searches of the suppression list initiated. */
117 static UWord em_supplist_searches = 0;
119 /* Stats: number of comparisons done during suppression list
120 searching. */
121 static UWord em_supplist_cmps = 0;
123 /*------------------------------------------------------------*/
124 /*--- Error type ---*/
125 /*------------------------------------------------------------*/
127 /* Errors. Extensible (via the 'extra' field). Tools can use a normal
128 enum (with element values in the normal range (0..)) for 'ekind'.
129 Functions for getting/setting the tool-relevant fields are in
130 include/pub_tool_errormgr.h.
132 When errors are found and recorded with VG_(maybe_record_error)(), all
133 the tool must do is pass in the four parameters; core will
134 allocate/initialise the error record.
136 struct _Error {
137 struct _Error* next;
138 // Unique tag. This gives the error a unique identity (handle) by
139 // which it can be referred to afterwords. Currently only used for
140 // XML printing.
141 UInt unique;
142 Int count;
143 // NULL if unsuppressed; or ptr to suppression record.
144 Supp* supp;
146 // The tool-specific part
147 ThreadId tid; // Initialised by core
148 ErrorKind ekind; // Used by ALL. Must be in the range (0..)
149 ExeContext* where; // Initialised by core
150 Addr addr; // Used frequently
151 const HChar* string; // Used frequently
152 void* extra; // For any tool-specific extras
156 ExeContext* VG_(get_error_where) ( const Error* err )
158 return err->where;
161 ErrorKind VG_(get_error_kind) ( const Error* err )
163 return err->ekind;
166 Addr VG_(get_error_address) ( const Error* err )
168 return err->addr;
171 const HChar* VG_(get_error_string) ( const Error* err )
173 return err->string;
176 void* VG_(get_error_extra) ( const Error* err )
178 return err->extra;
181 UInt VG_(get_n_errs_found)( void )
183 return n_errs_found;
186 UInt VG_(get_n_errs_shown)( void )
188 return n_errs_shown;
191 Bool VG_(found_or_suppressed_errs)( void )
193 return errors != NULL;
196 /*------------------------------------------------------------*/
197 /*--- Suppression type ---*/
198 /*------------------------------------------------------------*/
200 /* Note: it is imperative this doesn't overlap with (0..) at all, as tools
201 * effectively extend it by defining their own enums in the (0..) range. */
202 typedef
203 enum {
204 // Nb: thread errors are a relic of the time when Valgrind's core
205 // could detect them. This example is left commented-out as an
206 // example should new core errors ever be added.
207 ThreadSupp = -1, /* Matches ThreadErr */
208 FdBadCloseSupp = -2,
209 FdNotClosedSupp = -3
211 CoreSuppKind;
213 /* Max number of callers for context in a suppression is
214 VG_DEEPEST_BACKTRACE. */
216 /* For each caller specified for a suppression, record the nature of
217 the caller name. Not of interest to tools. */
218 typedef
219 enum {
220 NoName, /* Error case */
221 ObjName, /* Name is of an shared object file. */
222 FunName, /* Name is of a function. */
223 DotDotDot, /* Frame-level wildcard */
224 SrcName /* Name is of a src file. */
226 SuppLocTy;
228 typedef
229 struct {
230 SuppLocTy ty;
231 Bool name_is_simple_str; /* True if name is a string without
232 '?' and '*' wildcard characters. */
233 HChar* name; /* NULL for NoName and DotDotDot */
234 UInt lineno; /* Valid for SrcName. */
236 SuppLoc;
238 /* Suppressions. Tools can get/set tool-relevant parts with functions
239 declared in include/pub_tool_errormgr.h. Extensible via the 'extra' field.
240 Tools can use a normal enum (with element values in the normal range
241 (0..)) for 'skind'. */
242 struct _Supp {
243 struct _Supp* next;
244 HChar* sname; // The name by which the suppression is referred to.
245 Int count; // The number of times this error has been suppressed.
247 // Index in VG_(clo_suppressions) giving filename from which suppression
248 // was read, and the lineno in this file where sname was read.
249 Int clo_suppressions_i;
250 Int sname_lineno;
252 // Length of 'callers'
253 Int n_callers;
254 // Array of callers, for matching stack traces. First one (name of fn
255 // where err occurs) is mandatory; rest are optional.
256 SuppLoc* callers;
258 /* The tool-specific part */
259 SuppKind skind; // What kind of suppression. Must use the range (0..).
260 HChar* string; // String -- use is optional. NULL by default.
261 void* extra; // Anything else -- use is optional. NULL by default.
264 SuppKind VG_(get_supp_kind) ( const Supp* su )
266 return su->skind;
269 HChar* VG_(get_supp_string) ( const Supp* su )
271 return su->string;
274 void* VG_(get_supp_extra) ( const Supp* su )
276 return su->extra;
280 void VG_(set_supp_kind) ( Supp* su, SuppKind skind )
282 su->skind = skind;
285 void VG_(set_supp_string) ( Supp* su, HChar* string )
287 su->string = string;
290 void VG_(set_supp_extra) ( Supp* su, void* extra )
292 su->extra = extra;
296 /*------------------------------------------------------------*/
297 /*--- Helper fns ---*/
298 /*------------------------------------------------------------*/
300 // Only show core errors if the tool wants to, we're not running with -q,
301 // and were not outputting XML.
302 Bool VG_(showing_core_errors)(void)
304 return VG_(needs).core_errors && VG_(clo_verbosity) >= 1 && !VG_(clo_xml);
307 /* Compare errors, to detect duplicates.
309 static Bool eq_Error ( VgRes res, const Error* e1, const Error* e2 )
311 if (e1->ekind != e2->ekind)
312 return False;
313 if (!VG_(eq_ExeContext)(res, e1->where, e2->where))
314 return False;
316 if (e1->ekind >= 0) {
317 if (VG_(needs).tool_errors) {
318 return VG_TDICT_CALL(tool_eq_Error, res, e1, e2);
319 } else {
320 VG_(printf)("\nUnhandled error type: %u. VG_(needs).tool_errors\n"
321 "probably needs to be set.\n",
322 (UInt)e1->ekind);
323 VG_(core_panic)("unhandled error type");
325 } else {
326 return core_eq_Error(res, e1, e2);
331 /* Helper functions for suppression generation: print a single line of
332 a suppression pseudo-stack-trace, either in XML or text mode. It's
333 important that the behaviour of these two functions exactly
334 corresponds.
336 #define ERRTXT_LEN 4096
338 static void printSuppForIp_XML(UInt n, DiEpoch ep, Addr ip, void* uu_opaque)
340 const HChar *buf;
341 InlIPCursor* iipc = VG_(new_IIPC)(ep, ip);
342 do {
343 if ( VG_(get_fnname_no_cxx_demangle) (ep, ip, &buf, iipc) ) {
344 VG_(printf_xml)(" <sframe> <fun>%pS</fun> </sframe>\n", buf);
345 } else
346 if ( VG_(get_objname)(ep, ip, &buf) ) {
347 VG_(printf_xml)(" <sframe> <obj>%pS</obj> </sframe>\n", buf);
348 } else {
349 VG_(printf_xml)(" <sframe> <obj>*</obj> </sframe>\n");
351 } while (VG_(next_IIPC)(iipc));
352 VG_(delete_IIPC)(iipc);
355 static void printSuppForIp_nonXML(UInt n, DiEpoch ep, Addr ip, void* textV)
357 const HChar *buf;
358 XArray* /* of HChar */ text = (XArray*)textV;
359 InlIPCursor* iipc = VG_(new_IIPC)(ep, ip);
360 do {
361 if ( VG_(get_fnname_no_cxx_demangle) (ep, ip, &buf, iipc) ) {
362 VG_(xaprintf)(text, " fun:%s\n", buf);
363 } else
364 if ( VG_(get_objname)(ep, ip, &buf) ) {
365 VG_(xaprintf)(text, " obj:%s\n", buf);
366 } else {
367 VG_(xaprintf)(text, " obj:*\n");
369 } while (VG_(next_IIPC)(iipc));
370 VG_(delete_IIPC)(iipc);
373 /* Generate a suppression for an error, either in text or XML mode.
375 static void gen_suppression(const Error* err)
377 const HChar* name;
378 const HChar* component;
379 ExeContext* ec;
380 XArray* /* HChar */ text;
382 const HChar* dummy_name = "insert_a_suppression_name_here";
384 vg_assert(err);
386 ec = VG_(get_error_where)(err);
387 if (ec == NULL) {
388 /* This can happen with core errors for --track-fds=all
389 with "leaked" inherited file descriptors, which aren't
390 created in the current program. */
391 VG_(umsg)("(No origin, error cannot be suppressed)\n");
392 return;
395 if (err->ekind >= 0) {
396 name = VG_TDICT_CALL(tool_get_error_name, err);
397 if (NULL == name) {
398 VG_(umsg)("(%s does not allow error to be suppressed)\n",
399 VG_(details).name);
400 return;
402 } else {
403 name = core_get_error_name(err);
404 if (NULL == name) {
405 VG_(umsg)("(core error cannot be suppressed)\n");
406 return;
410 /* In XML mode, we also need to print the plain text version of the
411 suppresion in a CDATA section. What that really means is, we
412 need to generate the plaintext version both in XML and text
413 mode. So generate it into TEXT. */
414 text = VG_(newXA)( VG_(malloc), "errormgr.gen_suppression.1",
415 VG_(free), sizeof(HChar) );
417 /* Ok. Generate the plain text version into TEXT. */
418 if (err->ekind >= 0)
419 component = VG_(details).name;
420 else
421 component = "CoreError";
422 VG_(xaprintf)(text, "{\n");
423 VG_(xaprintf)(text, " <%s>\n", dummy_name);
424 VG_(xaprintf)(text, " %s:%s\n", component, name);
426 HChar *xtra = NULL;
427 SizeT xtra_size = 0;
428 SizeT num_written;
430 do {
431 xtra_size += 256;
432 xtra = VG_(realloc)("errormgr.gen_suppression.2", xtra,xtra_size);
433 if (err->ekind >= 0)
434 num_written = VG_TDICT_CALL(tool_get_extra_suppression_info,
435 err, xtra, xtra_size);
436 else
437 num_written = core_get_extra_suppression_info(err, xtra, xtra_size);
438 } while (num_written == xtra_size); // resize buffer and retry
440 // Ensure buffer is properly terminated
441 vg_assert(xtra[num_written] == '\0');
443 if (num_written)
444 VG_(xaprintf)(text, " %s\n", xtra);
446 // Print stack trace elements
447 UInt n_ips = VG_(get_ExeContext_n_ips)(ec);
448 vg_assert(n_ips > 0);
449 vg_assert(n_ips <= VG_DEEPEST_BACKTRACE);
450 VG_(apply_StackTrace)(printSuppForIp_nonXML,
451 text, VG_(get_ExeContext_epoch)(ec),
452 VG_(get_ExeContext_StackTrace)(ec),
453 n_ips);
455 VG_(xaprintf)(text, "}\n");
456 // zero terminate
457 VG_(xaprintf)(text, "%c", (HChar)0 );
458 // VG_(printf) of text
460 /* And now display it. */
461 if (! VG_(clo_xml) ) {
463 // the simple case
464 VG_(printf)("%s", (HChar*) VG_(indexXA)(text, 0) );
466 } else {
468 /* Now we have to print the XML directly. No need to go to the
469 effort of stuffing it in an XArray, since we won't need it
470 again. */
471 VG_(printf_xml)(" <suppression>\n");
472 VG_(printf_xml)(" <sname>%s</sname>\n", dummy_name);
473 VG_(printf_xml)(
474 " <skind>%pS:%pS</skind>\n", component, name);
475 if (num_written)
476 VG_(printf_xml)(" <skaux>%pS</skaux>\n", xtra);
478 // Print stack trace elements
479 VG_(apply_StackTrace)(printSuppForIp_XML,
480 NULL, VG_(get_ExeContext_epoch)(ec),
481 VG_(get_ExeContext_StackTrace)(ec),
482 VG_(get_ExeContext_n_ips)(ec));
484 // And now the cdata bit
485 // XXX FIXME! properly handle the case where the raw text
486 // itself contains "]]>", as specified in Protocol 4.
487 VG_(printf_xml)(" <rawtext>\n");
488 VG_(printf_xml)("<![CDATA[\n");
489 VG_(printf_xml)("%s", (HChar*) VG_(indexXA)(text, 0) );
490 VG_(printf_xml)("]]>\n");
491 VG_(printf_xml)(" </rawtext>\n");
492 VG_(printf_xml)(" </suppression>\n");
496 VG_(deleteXA)(text);
497 VG_(free)(xtra);
501 /* Figure out if we want to perform a given action for this error,
502 possibly by asking the user.
504 Bool VG_(is_action_requested) ( const HChar* action, Bool* clo )
506 HChar ch, ch2;
507 Int res;
509 /* First off, we shouldn't be asking the user anything if
510 we're in XML mode. */
511 if (VG_(clo_xml))
512 return False; /* That's a Nein, oder Nay as they say down here in B-W */
514 if (*clo == False)
515 return False;
517 VG_(umsg)("\n");
519 again:
520 VG_(printf)(
521 "==%d== "
522 "---- %s ? --- [Return/N/n/Y/y/C/c] ---- ",
523 VG_(getpid)(), action
526 res = VG_(read)(VG_(clo_input_fd), &ch, 1);
527 if (res != 1) goto ioerror;
528 /* res == 1 */
529 if (ch == '\n') return False;
530 if (ch != 'N' && ch != 'n' && ch != 'Y' && ch != 'y'
531 && ch != 'C' && ch != 'c') goto again;
533 res = VG_(read)(VG_(clo_input_fd), &ch2, 1);
534 if (res != 1) goto ioerror;
535 if (ch2 != '\n') goto again;
537 /* No, don't want to do action. */
538 if (ch == 'n' || ch == 'N') return False;
539 /* Yes, want to do action. */
540 if (ch == 'y' || ch == 'Y') return True;
541 /* No, don't want to do action, and don't ask again either. */
542 vg_assert(ch == 'c' || ch == 'C');
544 ioerror:
545 *clo = False;
546 return False;
550 /* Do actions on error, that is, immediately after an error is printed.
551 These are:
552 * possibly, call the GDB server
553 * possibly, generate a suppression.
555 static
556 void do_actions_on_error(const Error* err, Bool allow_db_attach, Bool count_error)
558 Bool still_noisy = True;
560 /* if user wants to debug from a certain error nr, then wait for gdb/vgdb */
561 if (VG_(clo_vgdb) != Vg_VgdbNo
562 && allow_db_attach
563 && VG_(clo_vgdb_error) <= n_errs_shown) {
564 if (!(VG_(clo_launched_with_multi)))
565 VG_(umsg)("(action on error) vgdb me ... \n");
566 VG_(gdbserver)( err->tid );
567 if (!(VG_(clo_launched_with_multi)))
568 VG_(umsg)("Continuing ...\n");
571 /* Or maybe we want to generate the error's suppression? */
572 if (VG_(clo_gen_suppressions) == 2
573 || (VG_(clo_gen_suppressions) == 1
574 && VG_(is_action_requested)( "Print suppression", &still_noisy ))
576 gen_suppression(err);
578 if (VG_(clo_gen_suppressions) == 1 && !still_noisy)
579 VG_(clo_gen_suppressions) = 0;
581 if (count_error && VG_(clo_exit_on_first_error)) {
582 if (VG_(clo_xml))
583 VG_(printf_xml)("</valgrindoutput>\n");
584 VG_(umsg)("\n");
585 VG_(umsg)("Exit program on first error (--exit-on-first-error=yes)\n");
586 VG_(client_exit)( VG_(clo_error_exitcode) );
591 /* Prints an error. Not entirely simple because of the differences
592 between XML and text mode output.
594 In XML mode:
596 * calls the tool's pre-show method, so the tool can create any
597 preamble ahead of the message, if it wants.
599 * prints the opening tag, and the <unique> and <tid> fields
601 * prints the tool-specific parts of the message
603 * if suppression generation is required, a suppression
605 * the closing tag
607 In text mode:
609 * calls the tool's pre-show method, so the tool can create any
610 preamble ahead of the message, if it wants.
612 * prints the tool-specific parts of the message
614 In both modes:
616 * calls do_actions_on_error. This optionally does a gdbserver call
617 and optionally prints a suppression; both of these may require user input.
619 static void pp_Error ( const Error* err, Bool allow_db_attach, Bool xml, Bool count_error )
621 /* If this fails, you probably specified your tool's method
622 dictionary incorrectly. */
623 vg_assert(VG_(needs).tool_errors || err->ekind < 0 /* core errors */);
625 if (xml) {
627 /* Ensure that suppression generation is either completely
628 enabled or completely disabled; either way, we won't require
629 any user input. m_main.process_cmd_line_options should
630 ensure the asserted condition holds. */
631 vg_assert( VG_(clo_gen_suppressions) == 0 /* disabled */
632 || VG_(clo_gen_suppressions) == 2 /* for all errors */ );
634 /* Pre-show it to the tool */
635 if (err->ekind >= 0)
636 VG_TDICT_CALL( tool_before_pp_Error, err );
637 else
638 core_before_pp_Error (err);
640 /* standard preamble */
641 VG_(printf_xml)("<error>\n");
642 VG_(printf_xml)(" <unique>0x%x</unique>\n", err->unique);
643 VG_(printf_xml)(" <tid>%u</tid>\n", err->tid);
644 ThreadState* tst = VG_(get_ThreadState)(err->tid);
645 if (tst->thread_name) {
646 VG_(printf_xml)(" <threadname>%s</threadname>\n", tst->thread_name);
649 /* actually print it */
650 if (err->ekind >= 0)
651 VG_TDICT_CALL( tool_pp_Error, err );
652 else
653 core_pp_Error (err);
655 if (VG_(clo_gen_suppressions) > 0)
656 gen_suppression(err);
658 /* postamble */
659 VG_(printf_xml)("</error>\n");
660 VG_(printf_xml)("\n");
662 } else {
664 if (VG_(clo_error_markers)[0])
665 VG_(umsg)("%s\n", VG_(clo_error_markers)[0]);
666 if (err->ekind >= 0)
667 VG_TDICT_CALL( tool_before_pp_Error, err );
668 else
669 core_before_pp_Error(err);
671 if (VG_(tdict).tool_show_ThreadIDs_for_errors
672 && err->tid > 0 && err->tid != last_tid_printed) {
673 ThreadState* tst = VG_(get_ThreadState)(err->tid);
674 if (tst->thread_name) {
675 VG_(umsg)("Thread %u %s:\n", err->tid, tst->thread_name );
676 } else {
677 VG_(umsg)("Thread %u:\n", err->tid );
679 last_tid_printed = err->tid;
682 if (err->ekind >= 0) {
683 VG_TDICT_CALL( tool_pp_Error, err );
684 VG_(umsg)("\n");
685 } else {
686 core_pp_Error(err);
688 if (VG_(clo_error_markers)[1])
689 VG_(umsg)("%s\n", VG_(clo_error_markers)[1]);
693 do_actions_on_error(err, allow_db_attach, count_error);
697 /* Construct an error */
698 static
699 void construct_error ( Error* err, ThreadId tid, ErrorKind ekind, Addr a,
700 const HChar* s, void* extra, ExeContext* where )
702 /* DO NOT MAKE unique_counter NON-STATIC */
703 static UInt unique_counter = 0;
705 vg_assert(tid < VG_N_THREADS);
707 /* Core-only parts */
708 err->unique = unique_counter++;
709 err->next = NULL;
710 err->supp = NULL;
711 err->count = 1;
712 err->tid = tid;
713 if (NULL == where && VG_(is_valid_tid)(tid))
714 err->where = VG_(record_ExeContext)( tid, 0 );
715 else
716 err->where = where;
718 /* Tool-relevant parts */
719 err->ekind = ekind;
720 err->addr = a;
721 err->extra = extra;
722 err->string = s;
724 /* sanity... */
725 vg_assert( tid < VG_N_THREADS );
730 /* Top-level entry point to the error management subsystem.
731 All detected errors are notified here; this routine decides if/when the
732 user should see the error. */
733 void VG_(maybe_record_error) ( ThreadId tid,
734 ErrorKind ekind, Addr a,
735 const HChar* s, void* extra )
737 Error err;
738 Error* p;
739 Error* p_prev;
740 UInt extra_size;
741 VgRes exe_res = Vg_MedRes;
742 static Bool stopping_message = False;
743 static Bool slowdown_message = False;
745 /* After M_COLLECT_NO_ERRORS_AFTER_SHOWN different errors have
746 been found, or M_COLLECT_NO_ERRORS_AFTER_FOUND total errors
747 have been found, just refuse to collect any more. This stops
748 the burden of the error-management system becoming excessive in
749 extremely buggy programs, although it does make it pretty
750 pointless to continue the Valgrind run after this point. */
751 if (VG_(clo_error_limit)
752 && (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN
753 || n_errs_found >= M_COLLECT_NO_ERRORS_AFTER_FOUND)
754 && !VG_(clo_xml)) {
755 if (!stopping_message) {
756 VG_(umsg)("\n");
758 if (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN) {
759 VG_(umsg)(
760 "More than %d different errors detected. "
761 "I'm not reporting any more.\n",
762 M_COLLECT_NO_ERRORS_AFTER_SHOWN );
763 } else {
764 VG_(umsg)(
765 "More than %d total errors detected. "
766 "I'm not reporting any more.\n",
767 M_COLLECT_NO_ERRORS_AFTER_FOUND );
770 VG_(umsg)("Final error counts will be inaccurate. "
771 "Go fix your program!\n");
772 VG_(umsg)("Rerun with --error-limit=no to disable "
773 "this cutoff. Note\n");
774 VG_(umsg)("that errors may occur in your program without "
775 "prior warning from\n");
776 VG_(umsg)("Valgrind, because errors are no longer "
777 "being displayed.\n");
778 VG_(umsg)("\n");
779 stopping_message = True;
781 return;
784 /* Ignore it if error acquisition is disabled for this thread. */
785 { ThreadState* tst = VG_(get_ThreadState)(tid);
786 if (tst->err_disablement_level > 0)
787 return;
790 /* After M_COLLECT_ERRORS_SLOWLY_AFTER different errors have
791 been found, be much more conservative about collecting new
792 ones. */
793 if (n_errs_shown >= M_COLLECT_ERRORS_SLOWLY_AFTER
794 && !VG_(clo_xml)) {
795 exe_res = Vg_LowRes;
796 if (!slowdown_message) {
797 VG_(umsg)("\n");
798 VG_(umsg)("More than %d errors detected. Subsequent errors\n",
799 M_COLLECT_ERRORS_SLOWLY_AFTER);
800 VG_(umsg)("will still be recorded, but in less "
801 "detail than before.\n");
802 slowdown_message = True;
806 /* Build ourselves the error */
807 construct_error ( &err, tid, ekind, a, s, extra, NULL );
809 /* First, see if we've got an error record matching this one. */
810 em_errlist_searches++;
811 p = errors;
812 p_prev = NULL;
813 while (p != NULL) {
814 em_errlist_cmps++;
815 if (eq_Error(exe_res, p, &err)) {
816 /* Found it. */
817 p->count++;
818 if (p->supp != NULL) {
819 /* Deal correctly with suppressed errors. */
820 p->supp->count++;
821 n_errs_suppressed++;
822 } else {
823 n_errs_found++;
826 /* Move p to the front of the list so that future searches
827 for it are faster. It also allows to print the last
828 error (see VG_(show_last_error). */
829 if (p_prev != NULL) {
830 vg_assert(p_prev->next == p);
831 p_prev->next = p->next;
832 p->next = errors;
833 errors = p;
836 return;
838 p_prev = p;
839 p = p->next;
842 /* Didn't see it. Copy and add. */
844 /* OK, we're really going to collect it. The context is on the stack and
845 will disappear shortly, so we must copy it. First do the main
846 (non-'extra') part.
848 Then VG_(tdict).tool_update_extra can update the 'extra' part. This
849 is for when there are more details to fill in which take time to work
850 out but don't affect our earlier decision to include the error -- by
851 postponing those details until now, we avoid the extra work in the
852 case where we ignore the error. Ugly.
854 Then, if there is an 'extra' part, copy it too, using the size that
855 VG_(tdict).tool_update_extra returned. Also allow for people using
856 the void* extra field for a scalar value like an integer.
859 /* copy main part */
860 p = VG_(malloc)("errormgr.mre.1", sizeof(Error));
861 *p = err;
863 /* update 'extra' */
864 if (ekind < 0) {
865 /* core error */
866 extra_size = core_update_extra (p);
867 } else {
868 vg_assert(VG_(needs).tool_errors);
869 extra_size = VG_TDICT_CALL(tool_update_extra, p);
872 /* copy the error string, if there is one.
873 note: if we would have many errors with big strings, using a
874 DedupPoolAlloc for these strings will avoid duplicating
875 such string in each error using it. */
876 if (NULL != p->string) {
877 p->string = VG_(strdup)("errormgr.mre.2", p->string);
880 /* copy block pointed to by 'extra', if there is one */
881 if (NULL != p->extra && 0 != extra_size) {
882 void* new_extra = VG_(malloc)("errormgr.mre.3", extra_size);
883 VG_(memcpy)(new_extra, p->extra, extra_size);
884 p->extra = new_extra;
887 p->next = errors;
888 p->supp = is_suppressible_error(&err);
889 errors = p;
890 if (p->supp == NULL) {
891 /* update stats */
892 n_err_contexts++;
893 n_errs_found++;
894 n_errs_shown++;
895 /* Actually show the error; more complex than you might think. */
896 pp_Error( p, /*allow_db_attach*/True, VG_(clo_xml), /* count_error */ True );
897 } else {
898 n_supp_contexts++;
899 n_errs_suppressed++;
900 p->supp->count++;
904 /* Second top-level entry point to the error management subsystem, for
905 errors that the tool wants to report immediately, eg. because they're
906 guaranteed to only happen once. This avoids all the recording and
907 comparing stuff. But they can be suppressed; returns True if it is
908 suppressed. Bool 'print_error' dictates whether to print the error.
909 Bool 'count_error' dictates whether to count the error in n_errs_found.
911 Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind, Addr a, const HChar* s,
912 void* extra, ExeContext* where, Bool print_error,
913 Bool allow_db_attach, Bool count_error )
915 Error err;
916 Supp *su;
918 /* Ignore it if error acquisition is disabled for this thread. */
919 ThreadState* tst = VG_(get_ThreadState)(tid);
920 if (tst->err_disablement_level > 0)
921 return False; /* ignored, not suppressed */
923 /* Build ourselves the error */
924 construct_error ( &err, tid, ekind, a, s, extra, where );
926 /* Unless it's suppressed, we're going to show it. Don't need to make
927 a copy, because it's only temporary anyway.
929 Then update the 'extra' part with VG_(tdict).tool_update_extra),
930 because that can have an affect on whether it's suppressed. Ignore
931 the size return value of VG_(tdict).tool_update_extra, because we're
932 not copying 'extra'. Similarly, 's' is also not copied. */
933 if (ekind >= 0)
934 (void)VG_TDICT_CALL(tool_update_extra, &err);
935 else
936 (void)core_update_extra(&err);
938 su = is_suppressible_error(&err);
939 if (NULL == su) {
940 if (count_error) {
941 n_errs_found++;
942 n_err_contexts++;
945 if (print_error) {
946 /* update stats */
947 n_errs_shown++;
948 /* Actually show the error; more complex than you might think. */
949 pp_Error(&err, allow_db_attach, VG_(clo_xml), count_error);
951 return False;
953 } else {
954 if (count_error) {
955 n_errs_suppressed++;
956 n_supp_contexts++;
958 su->count++;
959 return True;
964 /*------------------------------------------------------------*/
965 /*--- Core error fns ---*/
966 /*------------------------------------------------------------*/
968 static Bool is_fd_core_error (const Error *e)
970 return e->ekind == FdBadClose || e->ekind == FdNotClosed;
973 static Bool core_eq_Error (VgRes res, const Error *e1, const Error *e2)
975 if (is_fd_core_error(e1))
976 return fd_eq_Error (res, e1, e2);
977 else {
978 VG_(umsg)("FATAL: unknown core error kind: %d\n", e1->ekind );
979 VG_(exit)(1);
983 static void core_before_pp_Error (const Error *err)
985 if (is_fd_core_error(err))
986 fd_before_pp_Error(err);
987 else {
988 VG_(umsg)("FATAL: unknown core error kind: %d\n", err->ekind );
989 VG_(exit)(1);
993 static void core_pp_Error (const Error *err)
995 if (is_fd_core_error(err))
996 fd_pp_Error(err);
997 else {
998 VG_(umsg)("FATAL: unknown core error kind: %d\n", err->ekind );
999 VG_(exit)(1);
1003 static UInt core_update_extra (const Error *err)
1005 if (is_fd_core_error(err))
1006 return fd_update_extra(err);
1007 else {
1008 VG_(umsg)("FATAL: unknown core error kind: %d\n", err->ekind );
1009 VG_(exit)(1);
1013 static const HChar *core_get_error_name(const Error *err)
1015 switch (err->ekind) {
1016 case FdBadClose:
1017 return "FdBadClose";
1018 case FdNotClosed:
1019 return "FdNotClosed";
1020 default:
1021 VG_(umsg)("FATAL: unknown core error kind: %d\n", err->ekind );
1022 VG_(exit)(1);
1026 static Bool core_error_matches_suppression(const Error* err, const Supp* su)
1028 switch (su->skind) {
1029 case FdBadCloseSupp:
1030 return err->ekind == FdBadClose;
1031 case FdNotClosedSupp:
1032 return err->ekind == FdNotClosed;
1033 default:
1034 VG_(umsg)("FATAL: unknown core suppression kind: %d\n", su->skind );
1035 VG_(exit)(1);
1039 static SizeT core_get_extra_suppression_info(const Error *err,
1040 HChar* buf, Int nBuf)
1042 /* No core error has any extra suppression info at the moment. */
1043 buf[0] = '\0';
1044 return 0;
1047 static SizeT core_print_extra_suppression_use(const Supp* su,
1048 HChar* buf, Int nBuf)
1050 /* No core error has any extra suppression info at the moment. */
1051 buf[0] = '\0';
1052 return 0;
1056 /*------------------------------------------------------------*/
1057 /*--- Exported fns ---*/
1058 /*------------------------------------------------------------*/
1060 /* Show the used suppressions. Returns False if no suppression
1061 got used. */
1062 static Bool show_used_suppressions ( void )
1064 Supp *su;
1065 Bool any_supp;
1067 if (VG_(clo_xml))
1068 VG_(printf_xml)("<suppcounts>\n");
1070 any_supp = False;
1071 for (su = suppressions; su != NULL; su = su->next) {
1072 if (su->count <= 0)
1073 continue;
1074 if (VG_(clo_xml)) {
1075 VG_(printf_xml)( " <pair>\n"
1076 " <count>%d</count>\n"
1077 " <name>%pS</name>\n"
1078 " </pair>\n",
1079 su->count, su->sname );
1080 } else {
1081 HChar *xtra = NULL;
1082 Int xtra_size = 0;
1083 SizeT num_written;
1084 // blank line before the first shown suppression, if any
1085 if (!any_supp)
1086 VG_(dmsg)("\n");
1088 do {
1089 xtra_size += 256;
1090 xtra = VG_(realloc)("errormgr.sus.1", xtra, xtra_size);
1091 if (su->skind >= 0)
1092 num_written = VG_TDICT_CALL(tool_print_extra_suppression_use,
1093 su, xtra, xtra_size);
1094 else
1095 num_written = core_print_extra_suppression_use(su,
1096 xtra, xtra_size);
1097 } while (num_written == xtra_size); // resize buffer and retry
1099 // Ensure buffer is properly terminated
1100 vg_assert(xtra[num_written] == '\0');
1102 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1103 su->clo_suppressions_i);
1104 VG_(dmsg)("used_suppression: %6d %s %s:%d%s%s\n", su->count, su->sname,
1105 filename,
1106 su->sname_lineno,
1107 num_written ? " " : "", xtra);
1108 VG_(free)(xtra);
1110 any_supp = True;
1113 if (VG_(clo_xml))
1114 VG_(printf_xml)("</suppcounts>\n");
1116 return any_supp;
1119 /* See pub_core_errormgr.h. */
1120 void VG_(show_all_errors) ( Int verbosity, Bool xml, Int show_error_list)
1122 Int i, n_min;
1123 Error *p, *p_min;
1124 Bool any_supp;
1125 Bool any_error = False;
1126 UInt n_errs;
1128 if (verbosity == 0 && show_error_list == 0)
1129 return;
1131 /* If we're printing XML, just show the suppressions and stop. */
1132 if (xml) {
1133 if (show_error_list > 0)
1134 (void)show_used_suppressions();
1135 return;
1138 /* We only get here if not printing XML. */
1139 VG_(umsg)("ERROR SUMMARY: "
1140 "%u errors from %u contexts (suppressed: %u from %u)\n",
1141 n_errs_found, n_err_contexts,
1142 n_errs_suppressed, n_supp_contexts );
1144 if (show_error_list == 0)
1145 return;
1147 // We do the following if show_error_list > 0
1148 // or at -v or above, and only in non-XML mode.
1150 /* Print the contexts in order of increasing error count.
1151 The below implements this in a quadratic algorithm based on the assumption
1152 that there are not too many errors (including the suppressed if showing
1153 the suppressed errors) !
1154 Once an error is shown, we add a huge value to its count to filter it
1155 out.
1156 After having shown all errors, we reset count to the original value. */
1157 n_errs = n_err_contexts + (show_error_list < 2 ? 0 : n_errs_suppressed);
1158 for (i = 0; i < n_errs; i++) {
1159 n_min = (1 << 30) - 1;
1160 p_min = NULL;
1161 for (p = errors; p != NULL; p = p->next) {
1162 if (show_error_list < 2 && p->supp != NULL) continue;
1163 if (p->count < n_min) {
1164 n_min = p->count;
1165 p_min = p;
1168 // XXX: this isn't right. See bug 203651.
1169 if (p_min == NULL) continue; //VG_(core_panic)("show_all_errors()");
1171 any_error = True;
1172 VG_(umsg)("\n");
1173 VG_(umsg)("%d errors%s%s%s in context %d of %u:\n",
1174 p_min->count,
1175 p_min->supp == NULL ? "" : " (suppressed by ",
1176 p_min->supp == NULL ? "" : p_min->supp->sname,
1177 p_min->supp == NULL ? "" : ")",
1178 i+1, n_errs);
1179 pp_Error( p_min, False/*allow_db_attach*/, False /* xml */, True /* count_error */ );
1181 // We're not printing XML -- we'd have exited above if so.
1182 vg_assert(! xml);
1184 if ((i+1 == VG_(clo_dump_error))) {
1185 StackTrace ips = VG_(get_ExeContext_StackTrace)(p_min->where);
1186 VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to debugging*/,
1187 ips[0], /*debugging*/True, 0xFE/*verbosity*/,
1188 /*bbs_done*/0,
1189 /*allow redir?*/True);
1192 p_min->count = p_min->count + (1 << 30);
1195 /* reset the counts, otherwise a 2nd call does not show anything anymore */
1196 for (p = errors; p != NULL; p = p->next) {
1197 if (p->count >= (1 << 30))
1198 p->count = p->count - (1 << 30);
1202 any_supp = show_used_suppressions();
1204 if (any_supp)
1205 VG_(umsg)("\n");
1206 // reprint summary, so users don't have to scroll way up to find
1207 // the first printing
1208 if (any_supp || any_error)
1209 VG_(umsg)("ERROR SUMMARY: "
1210 "%u errors from %u contexts (suppressed: %u from %u)\n",
1211 n_errs_found, n_err_contexts, n_errs_suppressed,
1212 n_supp_contexts );
1215 void VG_(show_last_error) ( void )
1217 if (n_err_contexts == 0) {
1218 VG_(umsg)("No errors yet\n");
1219 return;
1222 pp_Error( errors, False/*allow_db_attach*/, False/*xml*/, True/*count_error*/ );
1226 /* Show occurrence counts of all errors, in XML form. */
1227 void VG_(show_error_counts_as_XML) ( void )
1229 Error* err;
1230 VG_(printf_xml)("<errorcounts>\n");
1231 for (err = errors; err != NULL; err = err->next) {
1232 if (err->supp != NULL)
1233 continue;
1234 if (err->count <= 0)
1235 continue;
1236 VG_(printf_xml)(" <pair>\n");
1237 VG_(printf_xml)(" <count>%d</count>\n", err->count);
1238 VG_(printf_xml)(" <unique>0x%x</unique>\n", err->unique);
1239 VG_(printf_xml)(" </pair>\n");
1241 VG_(printf_xml)("</errorcounts>\n");
1242 VG_(printf_xml)("\n");
1246 /*------------------------------------------------------------*/
1247 /*--- Suppression parsing ---*/
1248 /*------------------------------------------------------------*/
1250 /* Get the next char from fd into *out_buf. Returns 1 if success,
1251 0 if eof or < 0 if error. */
1253 static Int get_char ( Int fd, HChar* out_buf )
1255 Int r;
1256 static HChar buf[256];
1257 static Int buf_size = 0;
1258 static Int buf_used = 0;
1259 vg_assert(buf_size >= 0 && buf_size <= sizeof buf);
1260 vg_assert(buf_used >= 0 && buf_used <= buf_size);
1261 if (buf_used == buf_size) {
1262 r = VG_(read)(fd, buf, sizeof buf);
1263 if (r < 0) return r; /* read failed */
1264 vg_assert(r >= 0 && r <= sizeof buf);
1265 buf_size = r;
1266 buf_used = 0;
1268 if (buf_size == 0)
1269 return 0; /* eof */
1270 vg_assert(buf_size >= 0 && buf_size <= sizeof buf);
1271 vg_assert(buf_used >= 0 && buf_used < buf_size);
1272 *out_buf = buf[buf_used];
1273 buf_used++;
1274 return 1;
1277 // Get a non blank non comment line.
1278 // Returns True if eof.
1279 static Bool get_nbnc_line ( Int fd, HChar** bufpp, SizeT* nBufp, Int* lineno )
1281 HChar* buf = *bufpp;
1282 SizeT nBuf = *nBufp;
1283 HChar ch;
1284 Int n, i;
1286 vg_assert(lineno); // lineno needed to correctly track line numbers.
1288 while (True) {
1289 buf[0] = 0;
1290 /* First, read until a non-blank char appears. */
1291 while (True) {
1292 n = get_char(fd, &ch);
1293 if (n == 1 && !VG_(isspace)(ch)) break;
1294 if (n == 1 && ch == '\n')
1295 (*lineno)++;
1296 if (n <= 0) return True;
1299 /* Now, read the line into buf. */
1300 i = 0;
1301 buf[i++] = ch; buf[i] = 0;
1302 while (True) {
1303 n = get_char(fd, &ch);
1304 if (n <= 0) return False; /* the next call will return True */
1305 if (ch == '\n')
1306 (*lineno)++;
1307 if (ch == '\n') break;
1308 if (i > 0 && i == nBuf-1) {
1309 *nBufp = nBuf = nBuf * 2;
1310 #define RIDICULOUS 100000
1311 vg_assert2(nBuf < RIDICULOUS, // Just a sanity check, really.
1312 "VG_(get_line): line longer than %d chars, aborting\n",
1313 RIDICULOUS);
1314 *bufpp = buf = VG_(realloc)("errormgr.get_line.1", buf, nBuf);
1316 buf[i++] = ch; buf[i] = 0;
1318 while (i > 1 && VG_(isspace)(buf[i-1])) {
1319 i--; buf[i] = 0;
1322 // VG_(printf)("The line *%p %d is '%s'\n", lineno, *lineno, buf);
1323 /* Ok, we have a line. If a non-comment line, return.
1324 If a comment line, start all over again. */
1325 if (buf[0] != '#') return False;
1329 // True if buf starts with fun: or obj: or is ...
1330 static Bool is_location_line (const HChar* buf)
1332 return VG_(strncmp)(buf, "fun:", 4) == 0
1333 || VG_(strncmp)(buf, "obj:", 4) == 0
1334 || VG_(strcmp)(buf, "...") == 0;
1337 Bool VG_(get_line) ( Int fd, HChar** bufpp, SizeT* nBufp, Int* lineno )
1339 Bool eof = get_nbnc_line (fd, bufpp, nBufp, lineno);
1341 if (eof)
1342 return True;
1344 if (is_location_line(*bufpp))
1345 return True; // Not a extra suppr line
1346 else
1347 return False; // A suppression extra line
1350 /* True if s contains no wildcard (?, *) characters. */
1351 static Bool is_simple_str (const HChar *s)
1353 while (*s) {
1354 if (*s == '?' || *s == '*')
1355 return False;
1356 s++;
1358 return True;
1361 /* buf contains the raw name of a caller, supposedly either
1362 fun:some_function_name or
1363 obj:some_object_name or
1364 src:some_file_name or
1365 src:some_file_name:line# or
1367 Set p->ty and p->name accordingly.
1368 p->name is allocated and set to the string
1369 after the descriptor (fun:, obj:, or src: san line#) part.
1370 p->lineno is set to non-zero if line# specified; 0 otherwise.
1371 Returns False if failed.
1373 static Bool setLocationTy ( SuppLoc* p, const HChar *buf )
1375 if (VG_(strncmp)(buf, "fun:", 4) == 0) {
1376 p->name = VG_(strdup)("errormgr.sLTy.1", buf+4);
1377 p->name_is_simple_str = is_simple_str (p->name);
1378 p->ty = FunName;
1379 return True;
1381 if (VG_(strncmp)(buf, "obj:", 4) == 0) {
1382 p->name = VG_(strdup)("errormgr.sLTy.2", buf+4);
1383 p->name_is_simple_str = is_simple_str (p->name);
1384 p->ty = ObjName;
1385 return True;
1387 if (VG_(strncmp)(buf, "src:", 4) == 0) {
1388 p->name = VG_(strdup)("errormgr.sLTy.3", buf+4);
1389 p->name_is_simple_str = is_simple_str (p->name);
1390 p->ty = SrcName;
1391 HChar *s = VG_(strchr)(p->name, ':');
1392 if (s != NULL) {
1393 *s++ = '\0'; // trim colon
1394 p->lineno = (UInt) VG_(strtoll10)(s, NULL);
1395 } else {
1396 p->lineno = 0;
1398 return True;
1400 if (VG_(strcmp)(buf, "...") == 0) {
1401 p->name = NULL;
1402 p->name_is_simple_str = False;
1403 p->ty = DotDotDot;
1404 return True;
1406 VG_(printf)("location should be \"...\", or should start "
1407 "with \"fun:\", \"obj:\", or \"src:\"\n");
1408 return False;
1412 /* Look for "tool" in a string like "tool1,tool2,tool3" */
1413 static Bool tool_name_present(const HChar *name, const HChar *names)
1415 Bool found;
1416 HChar *s = NULL; /* Shut gcc up */
1417 Int len = VG_(strlen)(name);
1419 found = (NULL != (s = VG_(strstr)(names, name))
1420 && (s == names || *(s-1) == ',')
1421 && (*(s+len) == ',' || *(s+len) == '\0'));
1423 return found;
1426 /* Read suppressions from the file specified in
1427 VG_(clo_suppressions)[clo_suppressions_i]
1428 and place them in the suppressions list. If there's any difficulty
1429 doing this, just give up -- there's no point in trying to recover.
1431 static void load_one_suppressions_file ( Int clo_suppressions_i )
1433 const HChar* filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1434 clo_suppressions_i);
1435 SysRes sres;
1436 Int fd, i, j, lineno = 0;
1437 Bool got_a_location_line_read_by_tool;
1438 Bool eof;
1439 SizeT nBuf = 200;
1440 HChar* buf = VG_(malloc)("errormgr.losf.1", nBuf);
1441 HChar* tool_names;
1442 HChar* supp_name;
1443 const HChar* err_str = NULL;
1444 SuppLoc tmp_callers[VG_DEEPEST_BACKTRACE];
1446 // Check it's not a directory.
1447 if (VG_(is_dir)( filename )) {
1448 if (VG_(clo_xml))
1449 VG_(printf_xml)("</valgrindoutput>\n");
1450 VG_(umsg)("FATAL: suppressions file \"%s\" is a directory\n", filename );
1451 VG_(exit)(1);
1454 // Open the suppression file.
1455 sres = VG_(open)( filename, VKI_O_RDONLY, 0 );
1456 if (sr_isError(sres)) {
1457 if (VG_(clo_xml))
1458 VG_(printf_xml)("</valgrindoutput>\n");
1459 VG_(umsg)("FATAL: can't open suppressions file \"%s\"\n", filename );
1460 VG_(exit)(1);
1462 fd = sr_Res(sres);
1464 # define BOMB(S) { err_str = S; goto syntax_error; }
1466 while (True) {
1467 /* Assign and initialise the two suppression halves (core and tool) */
1468 Supp* supp;
1469 supp = VG_(malloc)("errormgr.losf.1", sizeof(Supp));
1470 supp->count = 0;
1472 // Initialise temporary reading-in buffer.
1473 for (i = 0; i < VG_DEEPEST_BACKTRACE; i++) {
1474 tmp_callers[i].ty = NoName;
1475 tmp_callers[i].name_is_simple_str = False;
1476 tmp_callers[i].name = NULL;
1479 supp->string = supp->extra = NULL;
1481 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1482 if (eof) {
1483 VG_(free)(supp);
1484 break;
1487 if (!VG_STREQ(buf, "{")) BOMB("expected '{' or end-of-file");
1489 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1491 if (eof || VG_STREQ(buf, "}")) BOMB("unexpected '}'");
1493 supp->sname = VG_(strdup)("errormgr.losf.2", buf);
1494 supp->clo_suppressions_i = clo_suppressions_i;
1495 supp->sname_lineno = lineno;
1497 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1499 if (eof) BOMB("unexpected end-of-file (expecting tool:suppr)");
1501 /* Check it has the "tool1,tool2,...:supp" form (look for ':') */
1502 i = 0;
1503 while (True) {
1504 if (buf[i] == ':') break;
1505 if (buf[i] == '\0') BOMB("malformed 'tool1,tool2,...:supp' line");
1506 i++;
1508 buf[i] = '\0'; /* Replace ':', splitting into two strings */
1510 tool_names = & buf[0];
1511 supp_name = & buf[i+1];
1513 if (VG_(needs).core_errors
1514 && tool_name_present("CoreError", tool_names)) {
1515 // A core suppression
1516 if (VG_STREQ(supp_name, "FdBadClose"))
1517 supp->skind = FdBadCloseSupp;
1518 else if (VG_STREQ(supp_name, "FdNotClosed"))
1519 supp->skind = FdNotClosedSupp;
1520 else
1521 BOMB("unknown core suppression type");
1523 else if (VG_(needs).tool_errors
1524 && tool_name_present(VG_(details).name, tool_names)) {
1525 // A tool suppression
1526 if (VG_TDICT_CALL(tool_recognised_suppression, supp_name, supp)) {
1527 /* Do nothing, function fills in supp->skind */
1528 } else {
1529 BOMB("unknown tool suppression type");
1532 else {
1533 // Ignore rest of suppression
1534 while (True) {
1535 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1536 if (eof) BOMB("unexpected end-of-file (when skipping suppression)");
1537 if (VG_STREQ(buf, "}"))
1538 break;
1540 VG_(free)(supp->sname);
1541 VG_(free)(supp);
1542 continue;
1545 buf[0] = 0;
1546 // tool_read_extra_suppression_info might read lines
1547 // from fd till a location line.
1548 if (VG_(needs).tool_errors
1549 && !VG_TDICT_CALL(tool_read_extra_suppression_info,
1550 fd, &buf, &nBuf, &lineno, supp)) {
1551 BOMB("bad or missing extra suppression info");
1554 // No core errors need to read extra suppression info
1556 got_a_location_line_read_by_tool = buf[0] != 0 && is_location_line(buf);
1558 /* the main frame-descriptor reading loop */
1559 i = 0;
1560 while (True) {
1561 if (got_a_location_line_read_by_tool) {
1562 got_a_location_line_read_by_tool = False;
1563 eof = False;
1564 } else {
1565 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1567 if (eof)
1568 BOMB("unexpected end-of-file (when reading stack trace)");
1569 if (VG_STREQ(buf, "}")) {
1570 if (i > 0) {
1571 break;
1572 } else {
1573 BOMB("missing stack trace");
1576 if (i == VG_DEEPEST_BACKTRACE)
1577 BOMB("too many callers in stack trace");
1578 if (i > 0 && i >= VG_(clo_backtrace_size))
1579 break;
1580 if (!setLocationTy(&(tmp_callers[i]), buf))
1581 BOMB("location should be \"...\", or should start "
1582 "with \"fun:\", \"obj:\", or \"src:\"");
1583 i++;
1586 // If the num callers is >= VG_(clo_backtrace_size), ignore any extra
1587 // lines and grab the '}'.
1588 if (!VG_STREQ(buf, "}")) {
1589 do {
1590 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1591 } while (!eof && !VG_STREQ(buf, "}"));
1594 // Reject entries which are entirely composed of frame
1595 // level wildcards.
1596 vg_assert(i > 0); // guaranteed by frame-descriptor reading loop
1597 for (j = 0; j < i; j++) {
1598 if (tmp_callers[j].ty == FunName || tmp_callers[j].ty == ObjName
1599 || tmp_callers[j].ty == SrcName) {
1600 break;
1602 vg_assert(tmp_callers[j].ty == DotDotDot);
1604 vg_assert(j >= 0 && j <= i);
1605 if (j == i) {
1606 // we didn't find any non-"..." entries
1607 BOMB("suppression must contain at least one location "
1608 "line which is not \"...\"");
1611 // Copy tmp_callers[] into supp->callers[]
1612 supp->n_callers = i;
1613 supp->callers = VG_(malloc)("errormgr.losf.4", i * sizeof(SuppLoc));
1614 for (i = 0; i < supp->n_callers; i++) {
1615 supp->callers[i] = tmp_callers[i];
1618 supp->next = suppressions;
1619 suppressions = supp;
1621 VG_(free)(buf);
1622 VG_(close)(fd);
1623 return;
1625 syntax_error:
1626 if (VG_(clo_xml))
1627 VG_(printf_xml)("</valgrindoutput>\n");
1628 VG_(umsg)("FATAL: in suppressions file \"%s\" near line %d:\n",
1629 filename, lineno );
1630 VG_(umsg)(" %s\n", err_str );
1632 VG_(close)(fd);
1633 VG_(umsg)("exiting now.\n");
1634 VG_(exit)(1);
1636 # undef BOMB
1639 void VG_(add_suppression_file)(const HChar *filename)
1641 HChar *f = VG_(strdup)("errormgr.addsup", filename);
1642 VG_(addToXA)(VG_(clo_suppressions), &f);
1643 if (load_suppressions_called)
1644 load_one_suppressions_file( VG_(sizeXA)(VG_(clo_suppressions)) - 1 );
1647 void VG_(load_suppressions) ( void )
1649 Int i;
1650 suppressions = NULL;
1651 load_suppressions_called = True;
1652 for (i = 0; i < VG_(sizeXA)(VG_(clo_suppressions)); i++) {
1653 if (VG_(clo_verbosity) > 1) {
1654 VG_(dmsg)("Reading suppressions file: %s\n",
1655 *(HChar**) VG_(indexXA)(VG_(clo_suppressions), i));
1657 load_one_suppressions_file( i );
1662 /*------------------------------------------------------------*/
1663 /*--- Matching errors to suppressions ---*/
1664 /*------------------------------------------------------------*/
1666 /* Parameterising functions for the use of VG_(generic_match) in
1667 suppression-vs-error matching. The suppression frames (SuppLoc)
1668 play the role of 'pattern'-element, and the error frames (IPs,
1669 hence simply Addrs) play the role of 'input'. In short then, we're
1670 matching a sequence of Addrs against a pattern composed of a
1671 sequence of SuppLocs.
1673 static Bool supploc_IsStar ( const void* supplocV )
1675 const SuppLoc* supploc = supplocV;
1676 return supploc->ty == DotDotDot;
1679 static Bool supploc_IsQuery ( const void* supplocV )
1681 return False; /* there's no '?' equivalent in the supp syntax */
1684 /* IPtoFunOrObjCompleter is a lazy completer of the IPs
1685 needed to match an error with the suppression patterns.
1686 The matching between an IP and a suppression pattern is done either
1687 with the IP function name or with the IP object name.
1688 First time the fun or obj name is needed for an IP member
1689 of a stack trace, it will be computed and stored in names.
1690 Also, if the IP corresponds to one or more inlined function calls,
1691 the inlined function names are expanded.
1692 The IPtoFunOrObjCompleter type is designed to minimise the nr of
1693 allocations and the nr of debuginfo search. */
1694 typedef
1695 struct {
1696 DiEpoch epoch; // used to interpret .ips
1697 StackTrace ips; // stack trace we are lazily completing.
1698 UWord n_ips; // nr of elements in ips.
1700 // VG_(generic_match) calls haveInputInpC to check
1701 // for the presence of an input element identified by ixInput
1702 // (i.e. a number that identifies the ixInput element of the
1703 // input sequence). It calls supp_pattEQinp to match this input
1704 // element with a pattern.
1705 // When inlining info is used to provide inlined function calls
1706 // in stacktraces, one IP in ips can be expanded in several
1707 // function names. So, each time input (or presence of input)
1708 // is requested by VG_(generic_match), we will expand
1709 // more IP of ips till we have expanded enough to reach the
1710 // input element requested (or we cannot expand anymore).
1712 UWord n_ips_expanded;
1713 // n_ips_expanded maintains the nr of elements in ips that we have
1714 // already expanded.
1715 UWord n_expanded;
1716 // n_expanded maintains the nr of elements resulting from the expansion
1717 // of the n_ips_expanded IPs. Without inlined function calls,
1718 // n_expanded == n_ips_expanded. With inlining info,
1719 // n_expanded >= n_ips_expanded.
1721 Int* n_offsets_per_ip;
1722 // n_offsets_per_ip[i] gives the nr of offsets in fun_offsets and
1723 // obj_offsets resulting of the expansion of ips[i].
1724 // The sum of all n_expanded_per_ip must be equal to n_expanded.
1725 // This array allows to retrieve the position in ips corresponding to
1726 // an ixInput.
1728 // size (in elements) of fun_offsets and obj_offsets.
1729 // (fun|obj)_offsets are reallocated if more space is needed
1730 // to expand an IP.
1731 UWord sz_offsets;
1733 Int* fun_offsets;
1734 // fun_offsets[ixInput] is the offset in names where the
1735 // function name for the ixInput element of the input sequence
1736 // can be found. As one IP of ips can be expanded in several
1737 // function calls due to inlined function calls, we can have more
1738 // elements in fun_offsets than in ips.
1739 // An offset -1 means the function name has not yet been computed.
1740 Int* obj_offsets;
1741 // Similarly, obj_offsets[ixInput] gives the offset for the
1742 // object name for ips[ixInput]
1743 // (-1 meaning object name not yet been computed).
1745 // All function names and object names will be concatenated
1746 // in names. names is reallocated on demand.
1747 HChar *names;
1748 Int names_szB; // size of names.
1749 Int names_free; // offset first free HChar in names.
1751 IPtoFunOrObjCompleter;
1753 static void pp_ip2fo (const IPtoFunOrObjCompleter* ip2fo)
1755 Int i, j;
1756 Int o;
1758 VG_(printf)("n_ips %lu n_ips_expanded %lu resulting in n_expanded %lu\n",
1759 ip2fo->n_ips, ip2fo->n_ips_expanded, ip2fo->n_expanded);
1760 for (i = 0; i < ip2fo->n_ips_expanded; i++) {
1761 o = 0;
1762 for (j = 0; j < i; j++)
1763 o += ip2fo->n_offsets_per_ip[j];
1764 VG_(printf)("ips %d 0x08%lx offset [%d,%d] ",
1765 i, ip2fo->ips[i],
1766 o, o+ip2fo->n_offsets_per_ip[i]-1);
1767 for (j = 0; j < ip2fo->n_offsets_per_ip[i]; j++) {
1768 VG_(printf)("%sfun:%s obj:%s\n",
1769 j == 0 ? "" : " ",
1770 ip2fo->fun_offsets[o+j] == -1 ?
1771 "<not expanded>" : &ip2fo->names[ip2fo->fun_offsets[o+j]],
1772 ip2fo->obj_offsets[o+j] == -1 ?
1773 "<not expanded>" : &ip2fo->names[ip2fo->obj_offsets[o+j]]);
1778 /* free the memory in ip2fo.
1779 At debuglog 4, su (or NULL) will be used to show the matching
1780 (or non matching) with ip2fo. */
1781 static void clearIPtoFunOrObjCompleter ( const Supp *su,
1782 IPtoFunOrObjCompleter* ip2fo)
1784 if (DEBUG_ERRORMGR || VG_(debugLog_getLevel)() >= 4) {
1785 if (su) {
1786 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1787 su->clo_suppressions_i);
1788 VG_(dmsg)("errormgr matching end suppression %s %s:%d matched:\n",
1789 su->sname,
1790 filename,
1791 su->sname_lineno);
1792 } else {
1793 VG_(dmsg)("errormgr matching end no suppression matched:\n");
1795 VG_(pp_StackTrace) (ip2fo->epoch, ip2fo->ips, ip2fo->n_ips);
1796 pp_ip2fo(ip2fo);
1798 if (ip2fo->n_offsets_per_ip) VG_(free)(ip2fo->n_offsets_per_ip);
1799 if (ip2fo->fun_offsets) VG_(free)(ip2fo->fun_offsets);
1800 if (ip2fo->obj_offsets) VG_(free)(ip2fo->obj_offsets);
1801 if (ip2fo->names) VG_(free)(ip2fo->names);
1804 /* Grow ip2fo->names to ensure we have NEEDED characters available
1805 in ip2fo->names and returns a pointer to the first free char. */
1806 static HChar* grow_names(IPtoFunOrObjCompleter* ip2fo, SizeT needed)
1808 if (ip2fo->names_szB
1809 < ip2fo->names_free + needed) {
1810 if (needed < ERRTXT_LEN) needed = ERRTXT_LEN;
1812 ip2fo->names
1813 = VG_(realloc)("foc_names",
1814 ip2fo->names,
1815 ip2fo->names_szB + needed);
1816 ip2fo->names_szB += needed;
1818 return ip2fo->names + ip2fo->names_free;
1821 /* foComplete returns the function name or object name for ixInput.
1822 If needFun, returns the function name for this input
1823 else returns the object name for this input.
1824 The function name or object name will be computed and added in
1825 names if not yet done. */
1826 static HChar* foComplete(IPtoFunOrObjCompleter* ip2fo,
1827 Int ixInput, Bool needFun)
1829 vg_assert (ixInput < ip2fo->n_expanded);
1830 vg_assert (VG_(clo_read_inline_info) || ixInput < ip2fo->n_ips);
1832 // ptr to the offset array for function offsets (if needFun)
1833 // or object offsets (if !needFun).
1834 Int** offsets;
1835 if (needFun)
1836 offsets = &ip2fo->fun_offsets;
1837 else
1838 offsets = &ip2fo->obj_offsets;
1840 // Complete Fun name or Obj name for IP if not yet done.
1841 if ((*offsets)[ixInput] == -1) {
1842 const HChar* caller;
1844 (*offsets)[ixInput] = ip2fo->names_free;
1845 if (DEBUG_ERRORMGR) VG_(printf)("marking %s ixInput %d offset %d\n",
1846 needFun ? "fun" : "obj",
1847 ixInput, ip2fo->names_free);
1848 if (needFun) {
1849 // With inline info, fn names must have been completed already.
1850 vg_assert (!VG_(clo_read_inline_info));
1851 /* Get the function name into 'caller_name', or "???"
1852 if unknown. */
1853 // Nb: C++-mangled names are used in suppressions. Do, though,
1854 // Z-demangle them, since otherwise it's possible to wind
1855 // up comparing "malloc" in the suppression against
1856 // "_vgrZU_libcZdsoZa_malloc" in the backtrace, and the
1857 // two of them need to be made to match.
1858 if (!VG_(get_fnname_no_cxx_demangle)(ip2fo->epoch,
1859 ip2fo->ips[ixInput],
1860 &caller,
1861 NULL))
1862 caller = "???";
1863 } else {
1864 /* Get the object name into 'caller_name', or "???"
1865 if unknown. */
1866 UWord i;
1867 UWord last_expand_pos_ips = 0;
1868 UWord pos_ips;
1870 /* First get the pos in ips corresponding to ixInput */
1871 for (pos_ips = 0; pos_ips < ip2fo->n_expanded; pos_ips++) {
1872 last_expand_pos_ips += ip2fo->n_offsets_per_ip[pos_ips];
1873 if (ixInput < last_expand_pos_ips)
1874 break;
1876 /* pos_ips is the position in ips corresponding to ixInput.
1877 last_expand_pos_ips is the last offset in fun/obj where
1878 ips[pos_ips] has been expanded. */
1880 if (!VG_(get_objname)(ip2fo->epoch, ip2fo->ips[pos_ips], &caller))
1881 caller = "???";
1883 // Have all inlined calls pointing at this object name
1884 for (i = last_expand_pos_ips - ip2fo->n_offsets_per_ip[pos_ips] + 1;
1885 i < last_expand_pos_ips;
1886 i++) {
1887 ip2fo->obj_offsets[i] = ip2fo->names_free;
1888 if (DEBUG_ERRORMGR)
1889 VG_(printf) (" set obj_offset %lu to %d\n",
1890 i, ip2fo->names_free);
1893 SizeT caller_len = VG_(strlen)(caller);
1894 HChar* caller_name = grow_names(ip2fo, caller_len + 1);
1895 VG_(strcpy)(caller_name, caller);
1896 ip2fo->names_free += caller_len + 1;
1897 if (DEBUG_ERRORMGR) pp_ip2fo(ip2fo);
1900 return ip2fo->names + (*offsets)[ixInput];
1903 // Grow fun and obj _offsets arrays to have at least n_req elements.
1904 // Ensure n_offsets_per_ip is allocated.
1905 static void grow_offsets(IPtoFunOrObjCompleter* ip2fo, Int n_req)
1907 Int i;
1909 // n_offsets_per_ip must always have the size of the ips array
1910 if (ip2fo->n_offsets_per_ip == NULL) {
1911 ip2fo->n_offsets_per_ip = VG_(malloc)("grow_offsets",
1912 ip2fo->n_ips * sizeof(Int));
1913 for (i = 0; i < ip2fo->n_ips; i++)
1914 ip2fo->n_offsets_per_ip[i] = 0;
1917 if (ip2fo->sz_offsets >= n_req)
1918 return;
1920 // Avoid too much re-allocation by allocating at least ip2fo->n_ips
1921 // elements and at least a few more elements than the current size.
1922 if (n_req < ip2fo->n_ips)
1923 n_req = ip2fo->n_ips;
1924 if (n_req < ip2fo->sz_offsets + 5)
1925 n_req = ip2fo->sz_offsets + 5;
1927 ip2fo->fun_offsets = VG_(realloc)("grow_offsets", ip2fo->fun_offsets,
1928 n_req * sizeof(Int));
1929 for (i = ip2fo->sz_offsets; i < n_req; i++)
1930 ip2fo->fun_offsets[i] = -1;
1932 ip2fo->obj_offsets = VG_(realloc)("grow_offsets", ip2fo->obj_offsets,
1933 n_req * sizeof(Int));
1934 for (i = ip2fo->sz_offsets; i < n_req; i++)
1935 ip2fo->obj_offsets[i] = -1;
1937 ip2fo->sz_offsets = n_req;
1940 // Expands more IPs from ip2fo->ips.
1941 static void expandInput (IPtoFunOrObjCompleter* ip2fo, UWord ixInput )
1943 while (ip2fo->n_ips_expanded < ip2fo->n_ips
1944 && ip2fo->n_expanded <= ixInput) {
1945 if (VG_(clo_read_inline_info)) {
1946 // Expand one more IP in one or more calls.
1947 const Addr IP = ip2fo->ips[ip2fo->n_ips_expanded];
1948 InlIPCursor *iipc;
1950 iipc = VG_(new_IIPC)(ip2fo->epoch, IP);
1951 // The only thing we really need is the nr of inlined fn calls
1952 // corresponding to the IP we will expand.
1953 // However, computing this is mostly the same as finding
1954 // the function name. So, let's directly complete the function name.
1955 do {
1956 const HChar *caller;
1957 grow_offsets(ip2fo, ip2fo->n_expanded+1);
1958 ip2fo->fun_offsets[ip2fo->n_expanded] = ip2fo->names_free;
1959 if (!VG_(get_fnname_no_cxx_demangle)(ip2fo->epoch, IP,
1960 &caller,
1961 iipc))
1962 caller = "???";
1963 SizeT caller_len = VG_(strlen)(caller);
1964 HChar* caller_name = grow_names(ip2fo, caller_len + 1);
1965 VG_(strcpy)(caller_name, caller);
1966 ip2fo->names_free += caller_len + 1;
1967 ip2fo->n_expanded++;
1968 ip2fo->n_offsets_per_ip[ip2fo->n_ips_expanded]++;
1969 } while (VG_(next_IIPC)(iipc));
1970 ip2fo->n_ips_expanded++;
1971 VG_(delete_IIPC) (iipc);
1972 } else {
1973 // Without inlined fn call info, expansion simply
1974 // consists in allocating enough elements in (fun|obj)_offsets.
1975 // The function or object names themselves will be completed
1976 // when requested.
1977 Int i;
1978 grow_offsets(ip2fo, ip2fo->n_ips);
1979 ip2fo->n_ips_expanded = ip2fo->n_ips;
1980 ip2fo->n_expanded = ip2fo->n_ips;
1981 for (i = 0; i < ip2fo->n_ips; i++)
1982 ip2fo->n_offsets_per_ip[i] = 1;
1987 static Bool haveInputInpC (void* inputCompleterV, UWord ixInput )
1989 IPtoFunOrObjCompleter* ip2fo = (IPtoFunOrObjCompleter*)inputCompleterV;
1990 expandInput(ip2fo, ixInput);
1991 return ixInput < ip2fo->n_expanded;
1994 static Bool supp_pattEQinp ( const void* supplocV, const void* addrV,
1995 void* inputCompleterV, UWord ixInput )
1997 const SuppLoc* supploc = (const SuppLoc*)supplocV; /* PATTERN */
1998 IPtoFunOrObjCompleter* ip2fo = (IPtoFunOrObjCompleter*)inputCompleterV;
1999 const HChar* funobjsrc_name; // Fun, Obj, or src file name.
2000 UInt src_lineno = 0;
2001 Bool ret;
2003 expandInput(ip2fo, ixInput);
2004 vg_assert(ixInput < ip2fo->n_expanded);
2006 /* So, does this IP address match this suppression-line? */
2007 switch (supploc->ty) {
2008 case DotDotDot:
2009 /* supp_pattEQinp is a callback from VG_(generic_match). As
2010 per the spec thereof (see include/pub_tool_seqmatch.h), we
2011 should never get called with a pattern value for which the
2012 _IsStar or _IsQuery function would return True. Hence
2013 this can't happen. */
2014 vg_assert(0);
2015 case ObjName:
2016 funobjsrc_name = foComplete(ip2fo, ixInput, False /*needFun*/);
2017 break;
2018 case FunName:
2019 funobjsrc_name = foComplete(ip2fo, ixInput, True /*needFun*/);
2020 break;
2021 case SrcName: {
2022 const HChar* src_dirname; // placeholder only
2023 ret = VG_(get_filename_linenum)(VG_(current_DiEpoch)(),
2024 ip2fo->ips[ixInput], &funobjsrc_name, &src_dirname, &src_lineno);
2025 if (!ret) {
2026 /* No file name found for location so no way this is a match. */
2027 return ret;
2029 break;
2031 default:
2032 vg_assert(0);
2035 /* So now we have the function or object name in funobjsrc_name, and
2036 the pattern (at the character level) to match against is in
2037 supploc->name. Hence (and leading to a re-entrant call of
2038 VG_(generic_match) if there is a wildcard character): */
2039 if (supploc->name_is_simple_str)
2040 ret = VG_(strcmp) (supploc->name, funobjsrc_name) == 0;
2041 else
2042 ret = VG_(string_match)(supploc->name, funobjsrc_name);
2043 if (ret && supploc->ty == SrcName && supploc->lineno != 0) {
2044 ret = (supploc->lineno == src_lineno);
2046 if (DEBUG_ERRORMGR)
2047 VG_(printf) ("supp_pattEQinp %s patt %s ixInput %lu value:%s (lineno:%u vs %u) match:%s\n",
2048 supploc->ty == FunName ? "fun" : (supploc->ty == SrcName ? "src" : "obj"),
2049 supploc->name, ixInput, funobjsrc_name,
2050 supploc->ty == SrcName ? supploc->lineno : 0,
2051 supploc->ty == SrcName ? src_lineno : 0,
2052 ret ? "yes" : "no");
2053 return ret;
2056 /////////////////////////////////////////////////////
2058 static Bool supp_matches_callers(IPtoFunOrObjCompleter* ip2fo,
2059 const Supp* su)
2061 /* Unwrap the args and set up the correct parameterisation of
2062 VG_(generic_match), using supploc_IsStar, supploc_IsQuery and
2063 supp_pattEQinp. */
2064 /* note, StackTrace ip2fo->ips === Addr* */
2065 SuppLoc* supps = su->callers;
2066 UWord n_supps = su->n_callers;
2067 UWord szbPatt = sizeof(SuppLoc);
2068 Bool matchAll = False; /* we just want to match a prefix */
2069 if (DEBUG_ERRORMGR) {
2070 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
2071 su->clo_suppressions_i);
2072 VG_(dmsg)(" errormgr Checking match with %s %s:%d\n",
2073 su->sname,
2074 filename,
2075 su->sname_lineno);
2077 return
2078 VG_(generic_match)(
2079 matchAll,
2080 /*PATT*/supps, szbPatt, n_supps, 0/*initial ixPatt*/,
2081 /*INPUT*/
2082 NULL, 0, 0, /* input/szbInput/nInput 0, as using an inputCompleter */
2083 0/*initial ixInput*/,
2084 supploc_IsStar, supploc_IsQuery, supp_pattEQinp,
2085 ip2fo, haveInputInpC
2089 /////////////////////////////////////////////////////
2091 static
2092 Bool supp_matches_error(const Supp* su, const Error* err)
2094 if (su->skind >= 0) {
2095 if (VG_(needs).tool_errors) {
2096 return VG_TDICT_CALL(tool_error_matches_suppression, err, su);
2097 } else {
2098 VG_(printf)(
2099 "\nUnhandled suppression type: %u. VG_(needs).tool_errors\n"
2100 "probably needs to be set.\n",
2101 (UInt)err->ekind);
2102 VG_(core_panic)("unhandled suppression type");
2104 } else {
2105 return core_error_matches_suppression(err, su);
2109 /////////////////////////////////////////////////////
2111 /* Does an error context match a suppression? ie is this a suppressible
2112 error? If so, return a pointer to the Supp record, otherwise NULL.
2113 Tries to minimise the number of symbol searches since they are expensive.
2115 static Supp* is_suppressible_error ( const Error* err )
2117 Supp* su;
2118 Supp* su_prev;
2120 IPtoFunOrObjCompleter ip2fo;
2121 /* Conceptually, ip2fo contains an array of function names and an array of
2122 object names, corresponding to the array of IP of err->where.
2123 These names are just computed 'on demand' (so once maximum),
2124 then stored (efficiently, avoiding too many allocs) in ip2fo to be
2125 re-usable for the matching of the same IP with the next suppression
2126 pattern.
2128 VG_(generic_match) gets this 'IP to Fun or Obj name completer' as one
2129 of its arguments. It will then pass it to the function
2130 supp_pattEQinp which will then lazily complete the IP function name or
2131 object name inside ip2fo. Next time the fun or obj name for the same
2132 IP is needed (i.e. for the matching with the next suppr pattern), then
2133 the fun or obj name will not be searched again in the debug info. */
2135 if (err->where == NULL)
2136 return NULL;
2138 /* stats gathering */
2139 em_supplist_searches++;
2141 /* Prepare the lazy input completer. */
2142 ip2fo.epoch = VG_(get_ExeContext_epoch)(err->where);
2143 ip2fo.ips = VG_(get_ExeContext_StackTrace)(err->where);
2144 ip2fo.n_ips = VG_(get_ExeContext_n_ips)(err->where);
2145 ip2fo.n_ips_expanded = 0;
2146 ip2fo.n_expanded = 0;
2147 ip2fo.sz_offsets = 0;
2148 ip2fo.n_offsets_per_ip = NULL;
2149 ip2fo.fun_offsets = NULL;
2150 ip2fo.obj_offsets = NULL;
2151 ip2fo.names = NULL;
2152 ip2fo.names_szB = 0;
2153 ip2fo.names_free = 0;
2155 /* See if the error context matches any suppression. */
2156 if (DEBUG_ERRORMGR || VG_(debugLog_getLevel)() >= 4)
2157 VG_(dmsg)("errormgr matching begin\n");
2158 su_prev = NULL;
2159 for (su = suppressions; su != NULL; su = su->next) {
2160 em_supplist_cmps++;
2161 if (supp_matches_error(su, err)
2162 && supp_matches_callers(&ip2fo, su)) {
2163 /* got a match. */
2164 /* Inform the tool that err is suppressed by su. */
2165 if (su->skind >= 0)
2166 (void)VG_TDICT_CALL(tool_update_extra_suppression_use, err, su);
2167 /* No core errors need to update extra suppression info */
2168 /* Move this entry to the head of the list
2169 in the hope of making future searches cheaper. */
2170 if (su_prev) {
2171 vg_assert(su_prev->next == su);
2172 su_prev->next = su->next;
2173 su->next = suppressions;
2174 suppressions = su;
2176 clearIPtoFunOrObjCompleter(su, &ip2fo);
2177 return su;
2179 su_prev = su;
2181 clearIPtoFunOrObjCompleter(NULL, &ip2fo);
2182 return NULL; /* no matches */
2185 /* Show accumulated error-list and suppression-list search stats.
2187 void VG_(print_errormgr_stats) ( void )
2189 VG_(dmsg)(
2190 " errormgr: %'lu supplist searches, %'lu comparisons during search\n",
2191 em_supplist_searches, em_supplist_cmps
2193 VG_(dmsg)(
2194 " errormgr: %'lu errlist searches, %'lu comparisons during search\n",
2195 em_errlist_searches, em_errlist_cmps
2199 /*--------------------------------------------------------------------*/
2200 /*--- end ---*/
2201 /*--------------------------------------------------------------------*/