1
2 /*--------------------------------------------------------------------*/
3 /*--- Management of error messages. m_errormgr.c ---*/
4 /*--------------------------------------------------------------------*/
5
6 /*
7 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
9
10 Copyright (C) 2000-2013 Julian Seward
11 jseward@acm.org
12
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of the
16 License, or (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful, but
19 WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, write to the Free Software
25 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
26 02111-1307, USA.
27
28 The GNU General Public License is contained in the file COPYING.
29 */
30
31 #include "pub_core_basics.h"
32 #include "pub_core_vki.h"
33 #include "pub_core_threadstate.h" // For VG_N_THREADS
34 #include "pub_core_debugger.h"
35 #include "pub_core_debuginfo.h"
36 #include "pub_core_debuglog.h"
37 #include "pub_core_errormgr.h"
38 #include "pub_core_execontext.h"
39 #include "pub_core_gdbserver.h"
40 #include "pub_core_libcbase.h"
41 #include "pub_core_libcassert.h"
42 #include "pub_core_libcfile.h"
43 #include "pub_core_libcprint.h"
44 #include "pub_core_libcproc.h" // For VG_(getpid)()
45 #include "pub_core_seqmatch.h"
46 #include "pub_core_mallocfree.h"
47 #include "pub_core_options.h"
48 #include "pub_core_stacktrace.h"
49 #include "pub_core_tooliface.h"
50 #include "pub_core_translate.h" // for VG_(translate)()
51 #include "pub_core_xarray.h" // VG_(xaprintf) et al
52
53 #define DEBUG_ERRORMGR 0 // set to 1 for heavyweight tracing
54
55 /*------------------------------------------------------------*/
56 /*--- Globals ---*/
57 /*------------------------------------------------------------*/
58
59 /* After this many different unsuppressed errors have been observed,
60 be more conservative about collecting new ones. */
61 #define M_COLLECT_ERRORS_SLOWLY_AFTER 100
62
63 /* After this many different unsuppressed errors have been observed,
64 stop collecting errors at all, and tell the user their program is
65 evidently a steaming pile of camel dung. */
66 #define M_COLLECT_NO_ERRORS_AFTER_SHOWN 1000
67
68 /* After this many total errors have been observed, stop collecting
69 errors at all. Counterpart to M_COLLECT_NO_ERRORS_AFTER_SHOWN. */
70 #define M_COLLECT_NO_ERRORS_AFTER_FOUND 10000000
71
72 /* The list of error contexts found, both suppressed and unsuppressed.
73 Initially empty, and grows as errors are detected. */
74 static Error* errors = NULL;
75
76 /* The list of suppression directives, as read from the specified
77 suppressions file. Note that the list gets rearranged as a result
78 of the searches done by is_suppressible_error(). */
79 static Supp* suppressions = NULL;
80
81 /* Running count of unsuppressed errors detected. */
82 static UInt n_errs_found = 0;
83
84 /* Running count of suppressed errors detected. */
85 static UInt n_errs_suppressed = 0;
86
87 /* Running count of errors shown. */
88 static UInt n_errs_shown = 0;
89
90 /* Running count of unsuppressed error contexts. */
91 static UInt n_err_contexts = 0;
92
93 /* Running count of suppressed error contexts. */
94 static UInt n_supp_contexts = 0;
95
96
97 /* forwards ... */
98 static Supp* is_suppressible_error ( const Error* err );
99
100 static ThreadId last_tid_printed = 1;
101
102 /* Stats: number of searches of the error list initiated. */
103 static UWord em_errlist_searches = 0;
104
105 /* Stats: number of comparisons done during error list
106 searching. */
107 static UWord em_errlist_cmps = 0;
108
109 /* Stats: number of searches of the suppression list initiated. */
110 static UWord em_supplist_searches = 0;
111
112 /* Stats: number of comparisons done during suppression list
113 searching. */
114 static UWord em_supplist_cmps = 0;
115
116 /*------------------------------------------------------------*/
117 /*--- Error type ---*/
118 /*------------------------------------------------------------*/
119
120 /* Errors. Extensible (via the 'extra' field). Tools can use a normal
121 enum (with element values in the normal range (0..)) for 'ekind'.
122 Functions for getting/setting the tool-relevant fields are in
123 include/pub_tool_errormgr.h.
124
125 When errors are found and recorded with VG_(maybe_record_error)(), all
126 the tool must do is pass in the four parameters; core will
127 allocate/initialise the error record.
128 */
129 struct _Error {
130 struct _Error* next;
131 // Unique tag. This gives the error a unique identity (handle) by
132 // which it can be referred to afterwords. Currently only used for
133 // XML printing.
134 UInt unique;
135 // NULL if unsuppressed; or ptr to suppression record.
136 Supp* supp;
137 Int count;
138
139 // The tool-specific part
140 ThreadId tid; // Initialised by core
141 ExeContext* where; // Initialised by core
142 ErrorKind ekind; // Used by ALL. Must be in the range (0..)
143 Addr addr; // Used frequently
144 const HChar* string; // Used frequently
145 void* extra; // For any tool-specific extras
146 };
147
148
VG_(get_error_where)149 ExeContext* VG_(get_error_where) ( const Error* err )
150 {
151 return err->where;
152 }
153
VG_(get_error_kind)154 ErrorKind VG_(get_error_kind) ( const Error* err )
155 {
156 return err->ekind;
157 }
158
VG_(get_error_address)159 Addr VG_(get_error_address) ( const Error* err )
160 {
161 return err->addr;
162 }
163
VG_(get_error_string)164 const HChar* VG_(get_error_string) ( const Error* err )
165 {
166 return err->string;
167 }
168
VG_(get_error_extra)169 void* VG_(get_error_extra) ( const Error* err )
170 {
171 return err->extra;
172 }
173
VG_(get_n_errs_found)174 UInt VG_(get_n_errs_found)( void )
175 {
176 return n_errs_found;
177 }
178
VG_(get_n_errs_shown)179 UInt VG_(get_n_errs_shown)( void )
180 {
181 return n_errs_shown;
182 }
183
184 /*------------------------------------------------------------*/
185 /*--- Suppression type ---*/
186 /*------------------------------------------------------------*/
187
188 /* Note: it is imperative this doesn't overlap with (0..) at all, as tools
189 * effectively extend it by defining their own enums in the (0..) range. */
190 typedef
191 enum {
192 // Nb: thread errors are a relic of the time when Valgrind's core
193 // could detect them. This example is left commented-out as an
194 // example should new core errors ever be added.
195 ThreadSupp = -1, /* Matches ThreadErr */
196 }
197 CoreSuppKind;
198
199 /* Max number of callers for context in a suppression. */
200 #define VG_MAX_SUPP_CALLERS 24
201
202 /* For each caller specified for a suppression, record the nature of
203 the caller name. Not of interest to tools. */
204 typedef
205 enum {
206 NoName, /* Error case */
207 ObjName, /* Name is of an shared object file. */
208 FunName, /* Name is of a function. */
209 DotDotDot /* Frame-level wildcard */
210 }
211 SuppLocTy;
212
213 typedef
214 struct {
215 SuppLocTy ty;
216 Bool name_is_simple_str; /* True if name is a string without
217 '?' and '*' wildcard characters. */
218 HChar* name; /* NULL for NoName and DotDotDot */
219 }
220 SuppLoc;
221
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 Int count; // The number of times this error has been suppressed.
229 HChar* sname; // The name by which the suppression is referred to.
230
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;
235
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;
241
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.
246 };
247
VG_(get_supp_kind)248 SuppKind VG_(get_supp_kind) ( const Supp* su )
249 {
250 return su->skind;
251 }
252
VG_(get_supp_string)253 HChar* VG_(get_supp_string) ( const Supp* su )
254 {
255 return su->string;
256 }
257
VG_(get_supp_extra)258 void* VG_(get_supp_extra) ( const Supp* su )
259 {
260 return su->extra;
261 }
262
263
VG_(set_supp_kind)264 void VG_(set_supp_kind) ( Supp* su, SuppKind skind )
265 {
266 su->skind = skind;
267 }
268
VG_(set_supp_string)269 void VG_(set_supp_string) ( Supp* su, HChar* string )
270 {
271 su->string = string;
272 }
273
VG_(set_supp_extra)274 void VG_(set_supp_extra) ( Supp* su, void* extra )
275 {
276 su->extra = extra;
277 }
278
279
280 /*------------------------------------------------------------*/
281 /*--- Helper fns ---*/
282 /*------------------------------------------------------------*/
283
284 // Only show core errors if the tool wants to, we're not running with -q,
285 // and were not outputting XML.
VG_(showing_core_errors)286 Bool VG_(showing_core_errors)(void)
287 {
288 return VG_(needs).core_errors && VG_(clo_verbosity) >= 1 && !VG_(clo_xml);
289 }
290
291 /* Compare errors, to detect duplicates.
292 */
eq_Error(VgRes res,const Error * e1,const Error * e2)293 static Bool eq_Error ( VgRes res, const Error* e1, const Error* e2 )
294 {
295 if (e1->ekind != e2->ekind)
296 return False;
297 if (!VG_(eq_ExeContext)(res, e1->where, e2->where))
298 return False;
299
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 e1->ekind);
312 VG_(core_panic)("unhandled error type");
313 }
314 }
315 }
316
317
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.
322 */
323 #define ERRTXT_LEN 4096
324
printSuppForIp_XML(UInt n,Addr ip,void * uu_opaque)325 static void printSuppForIp_XML(UInt n, Addr ip, void* uu_opaque)
326 {
327 const HChar *buf;
328 InlIPCursor* iipc = VG_(new_IIPC)(ip);
329 do {
330 if ( VG_(get_fnname_no_cxx_demangle) (ip, &buf, iipc) ) {
331 VG_(printf_xml)(" <sframe> <fun>%pS</fun> </sframe>\n", buf);
332 } else
333 if ( VG_(get_objname)(ip, &buf) ) {
334 VG_(printf_xml)(" <sframe> <obj>%pS</obj> </sframe>\n", buf);
335 } else {
336 VG_(printf_xml)(" <sframe> <obj>*</obj> </sframe>\n");
337 }
338 } while (VG_(next_IIPC)(iipc));
339 VG_(delete_IIPC)(iipc);
340 }
341
printSuppForIp_nonXML(UInt n,Addr ip,void * textV)342 static void printSuppForIp_nonXML(UInt n, Addr ip, void* textV)
343 {
344 const HChar *buf;
345 XArray* /* of HChar */ text = (XArray*)textV;
346 InlIPCursor* iipc = VG_(new_IIPC)(ip);
347 do {
348 if ( VG_(get_fnname_no_cxx_demangle) (ip, &buf, iipc) ) {
349 VG_(xaprintf)(text, " fun:%s\n", buf);
350 } else
351 if ( VG_(get_objname)(ip, &buf) ) {
352 VG_(xaprintf)(text, " obj:%s\n", buf);
353 } else {
354 VG_(xaprintf)(text, " obj:*\n");
355 }
356 } while (VG_(next_IIPC)(iipc));
357 VG_(delete_IIPC)(iipc);
358 }
359
360 /* Generate a suppression for an error, either in text or XML mode.
361 */
gen_suppression(const Error * err)362 static void gen_suppression(const Error* err)
363 {
364 const HChar* name;
365 ExeContext* ec;
366 XArray* /* HChar */ text;
367
368 const HChar* dummy_name = "insert_a_suppression_name_here";
369
370 vg_assert(err);
371
372 ec = VG_(get_error_where)(err);
373 vg_assert(ec);
374
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;
380 }
381
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) );
388
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);
393
394 HChar *xtra = NULL;
395 SizeT xtra_size = 0;
396 SizeT num_written;
397
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
404
405 // Ensure buffer is properly terminated
406 vg_assert(xtra[num_written] == '\0');
407
408 if (num_written)
409 VG_(xaprintf)(text, " %s\n", xtra);
410
411 // Print stack trace elements
412 UInt n_ips = VG_(get_ExeContext_n_ips)(ec);
413 vg_assert(n_ips > 0);
414 if (n_ips > VG_MAX_SUPP_CALLERS)
415 n_ips = VG_MAX_SUPP_CALLERS;
416 VG_(apply_StackTrace)(printSuppForIp_nonXML,
417 text,
418 VG_(get_ExeContext_StackTrace)(ec),
419 n_ips);
420
421 VG_(xaprintf)(text, "}\n");
422 // zero terminate
423 VG_(xaprintf)(text, "%c", (HChar)0 );
424 // VG_(printf) of text
425
426 /* And now display it. */
427 if (! VG_(clo_xml) ) {
428
429 // the simple case
430 VG_(printf)("%s", (HChar*) VG_(indexXA)(text, 0) );
431
432 } else {
433
434 /* Now we have to print the XML directly. No need to go to the
435 effort of stuffing it in an XArray, since we won't need it
436 again. */
437 VG_(printf_xml)(" <suppression>\n");
438 VG_(printf_xml)(" <sname>%s</sname>\n", dummy_name);
439 VG_(printf_xml)(
440 " <skind>%pS:%pS</skind>\n", VG_(details).name, name);
441 if (num_written)
442 VG_(printf_xml)(" <skaux>%pS</skaux>\n", xtra);
443
444 // Print stack trace elements
445 VG_(apply_StackTrace)(printSuppForIp_XML,
446 NULL,
447 VG_(get_ExeContext_StackTrace)(ec),
448 VG_(get_ExeContext_n_ips)(ec));
449
450 // And now the cdata bit
451 // XXX FIXME! properly handle the case where the raw text
452 // itself contains "]]>", as specified in Protocol 4.
453 VG_(printf_xml)(" <rawtext>\n");
454 VG_(printf_xml)("<![CDATA[\n");
455 VG_(printf_xml)("%s", (HChar*) VG_(indexXA)(text, 0) );
456 VG_(printf_xml)("]]>\n");
457 VG_(printf_xml)(" </rawtext>\n");
458 VG_(printf_xml)(" </suppression>\n");
459
460 }
461
462 VG_(deleteXA)(text);
463 VG_(free)(xtra);
464 }
465
466
467 /* Figure out if we want to perform a given action for this error,
468 possibly by asking the user.
469 */
VG_(is_action_requested)470 Bool VG_(is_action_requested) ( const HChar* action, Bool* clo )
471 {
472 HChar ch, ch2;
473 Int res;
474
475 /* First off, we shouldn't be asking the user anything if
476 we're in XML mode. */
477 if (VG_(clo_xml))
478 return False; /* That's a Nein, oder Nay as they say down here in B-W */
479
480 if (*clo == False)
481 return False;
482
483 VG_(umsg)("\n");
484
485 again:
486 VG_(printf)(
487 "==%d== "
488 "---- %s ? --- [Return/N/n/Y/y/C/c] ---- ",
489 VG_(getpid)(), action
490 );
491
492 res = VG_(read)(VG_(clo_input_fd), &ch, 1);
493 if (res != 1) goto ioerror;
494 /* res == 1 */
495 if (ch == '\n') return False;
496 if (ch != 'N' && ch != 'n' && ch != 'Y' && ch != 'y'
497 && ch != 'C' && ch != 'c') goto again;
498
499 res = VG_(read)(VG_(clo_input_fd), &ch2, 1);
500 if (res != 1) goto ioerror;
501 if (ch2 != '\n') goto again;
502
503 /* No, don't want to do action. */
504 if (ch == 'n' || ch == 'N') return False;
505 /* Yes, want to do action. */
506 if (ch == 'y' || ch == 'Y') return True;
507 /* No, don't want to do action, and don't ask again either. */
508 vg_assert(ch == 'c' || ch == 'C');
509
510 ioerror:
511 *clo = False;
512 return False;
513 }
514
515
516 /* Do text-mode actions on error, that is, immediately after an error
517 is printed. These are:
518 * possibly, attach to a debugger
519 * possibly, generate a suppression.
520 Note this should not be called in XML mode!
521 */
522 static
do_actions_on_error(const Error * err,Bool allow_db_attach)523 void do_actions_on_error(const Error* err, Bool allow_db_attach)
524 {
525 Bool still_noisy = True;
526
527 /* if user wants to debug from a certain error nr, then wait for gdb/vgdb */
528 if (VG_(clo_vgdb) != Vg_VgdbNo
529 && allow_db_attach
530 && VG_(dyn_vgdb_error) <= n_errs_shown) {
531 VG_(umsg)("(action on error) vgdb me ... \n");
532 VG_(gdbserver)( err->tid );
533 VG_(umsg)("Continuing ...\n");
534 }
535
536 /* Perhaps we want a debugger attach at this point? */
537 /* GDBTD ??? maybe we should/could remove the below assuming the
538 gdbserver interface is better ??? */
539 if (allow_db_attach &&
540 VG_(is_action_requested)( "Attach to debugger", & VG_(clo_db_attach) ))
541 {
542 if (0) VG_(printf)("starting debugger\n");
543 VG_(start_debugger)( err->tid );
544 }
545 /* Or maybe we want to generate the error's suppression? */
546 if (VG_(clo_gen_suppressions) == 2
547 || (VG_(clo_gen_suppressions) == 1
548 && VG_(is_action_requested)( "Print suppression", &still_noisy ))
549 ) {
550 gen_suppression(err);
551 }
552 if (VG_(clo_gen_suppressions) == 1 && !still_noisy)
553 VG_(clo_gen_suppressions) = 0;
554 }
555
556
557 /* Prints an error. Not entirely simple because of the differences
558 between XML and text mode output.
559
560 In XML mode:
561
562 * calls the tool's pre-show method, so the tool can create any
563 preamble ahead of the message, if it wants.
564
565 * prints the opening tag, and the <unique> and <tid> fields
566
567 * prints the tool-specific parts of the message
568
569 * if suppression generation is required, a suppression
570
571 * the closing tag
572
573 In text mode:
574
575 * calls the tool's pre-show method, so the tool can create any
576 preamble ahead of the message, if it wants.
577
578 * prints the tool-specific parts of the message
579
580 * calls do_actions_on_error. This optionally does a gdbserver call
581 and optionally prints a suppression; both of these may require user input.
582 */
pp_Error(const Error * err,Bool allow_db_attach,Bool xml)583 static void pp_Error ( const Error* err, Bool allow_db_attach, Bool xml )
584 {
585 /* If this fails, you probably specified your tool's method
586 dictionary incorrectly. */
587 vg_assert(VG_(needs).tool_errors);
588
589 if (xml) {
590
591 /* Ensure that suppression generation is either completely
592 enabled or completely disabled; either way, we won't require
593 any user input. m_main.process_cmd_line_options should
594 ensure the asserted condition holds. */
595 vg_assert( VG_(clo_gen_suppressions) == 0 /* disabled */
596 || VG_(clo_gen_suppressions) == 2 /* for all errors */ );
597
598 /* Pre-show it to the tool */
599 VG_TDICT_CALL( tool_before_pp_Error, err );
600
601 /* standard preamble */
602 VG_(printf_xml)("<error>\n");
603 VG_(printf_xml)(" <unique>0x%x</unique>\n", err->unique);
604 VG_(printf_xml)(" <tid>%d</tid>\n", err->tid);
605 ThreadState* tst = VG_(get_ThreadState)(err->tid);
606 if (tst->thread_name) {
607 VG_(printf_xml)(" <threadname>%s</threadname>\n", tst->thread_name);
608 }
609
610 /* actually print it */
611 VG_TDICT_CALL( tool_pp_Error, err );
612
613 if (VG_(clo_gen_suppressions) > 0)
614 gen_suppression(err);
615
616 /* postamble */
617 VG_(printf_xml)("</error>\n");
618 VG_(printf_xml)("\n");
619
620 } else {
621
622 if (VG_(clo_error_markers)[0])
623 VG_(umsg)("%s\n", VG_(clo_error_markers)[0]);
624 VG_TDICT_CALL( tool_before_pp_Error, err );
625
626 if (VG_(tdict).tool_show_ThreadIDs_for_errors
627 && err->tid > 0 && err->tid != last_tid_printed) {
628 ThreadState* tst = VG_(get_ThreadState)(err->tid);
629 if (tst->thread_name) {
630 VG_(umsg)("Thread %d %s:\n", err->tid, tst->thread_name );
631 } else {
632 VG_(umsg)("Thread %d:\n", err->tid );
633 }
634 last_tid_printed = err->tid;
635 }
636
637 VG_TDICT_CALL( tool_pp_Error, err );
638 VG_(umsg)("\n");
639 if (VG_(clo_error_markers)[1])
640 VG_(umsg)("%s\n", VG_(clo_error_markers)[1]);
641
642 }
643
644 do_actions_on_error(err, allow_db_attach);
645 }
646
647
648 /* Construct an error */
649 static
construct_error(Error * err,ThreadId tid,ErrorKind ekind,Addr a,const HChar * s,void * extra,ExeContext * where)650 void construct_error ( Error* err, ThreadId tid, ErrorKind ekind, Addr a,
651 const HChar* s, void* extra, ExeContext* where )
652 {
653 /* DO NOT MAKE unique_counter NON-STATIC */
654 static UInt unique_counter = 0;
655
656 vg_assert(tid < VG_N_THREADS);
657
658 /* Core-only parts */
659 err->unique = unique_counter++;
660 err->next = NULL;
661 err->supp = NULL;
662 err->count = 1;
663 err->tid = tid;
664 if (NULL == where)
665 err->where = VG_(record_ExeContext)( tid, 0 );
666 else
667 err->where = where;
668
669 /* Tool-relevant parts */
670 err->ekind = ekind;
671 err->addr = a;
672 err->extra = extra;
673 err->string = s;
674
675 /* sanity... */
676 vg_assert( tid < VG_N_THREADS );
677 }
678
679
680
681 /* Top-level entry point to the error management subsystem.
682 All detected errors are notified here; this routine decides if/when the
683 user should see the error. */
VG_(maybe_record_error)684 void VG_(maybe_record_error) ( ThreadId tid,
685 ErrorKind ekind, Addr a,
686 const HChar* s, void* extra )
687 {
688 Error err;
689 Error* p;
690 Error* p_prev;
691 UInt extra_size;
692 VgRes exe_res = Vg_MedRes;
693 static Bool stopping_message = False;
694 static Bool slowdown_message = False;
695
696 /* After M_COLLECT_NO_ERRORS_AFTER_SHOWN different errors have
697 been found, or M_COLLECT_NO_ERRORS_AFTER_FOUND total errors
698 have been found, just refuse to collect any more. This stops
699 the burden of the error-management system becoming excessive in
700 extremely buggy programs, although it does make it pretty
701 pointless to continue the Valgrind run after this point. */
702 if (VG_(clo_error_limit)
703 && (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN
704 || n_errs_found >= M_COLLECT_NO_ERRORS_AFTER_FOUND)
705 && !VG_(clo_xml)) {
706 if (!stopping_message) {
707 VG_(umsg)("\n");
708
709 if (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN) {
710 VG_(umsg)(
711 "More than %d different errors detected. "
712 "I'm not reporting any more.\n",
713 M_COLLECT_NO_ERRORS_AFTER_SHOWN );
714 } else {
715 VG_(umsg)(
716 "More than %d total errors detected. "
717 "I'm not reporting any more.\n",
718 M_COLLECT_NO_ERRORS_AFTER_FOUND );
719 }
720
721 VG_(umsg)("Final error counts will be inaccurate. "
722 "Go fix your program!\n");
723 VG_(umsg)("Rerun with --error-limit=no to disable "
724 "this cutoff. Note\n");
725 VG_(umsg)("that errors may occur in your program without "
726 "prior warning from\n");
727 VG_(umsg)("Valgrind, because errors are no longer "
728 "being displayed.\n");
729 VG_(umsg)("\n");
730 stopping_message = True;
731 }
732 return;
733 }
734
735 /* Ignore it if error acquisition is disabled for this thread. */
736 { ThreadState* tst = VG_(get_ThreadState)(tid);
737 if (tst->err_disablement_level > 0)
738 return;
739 }
740
741 /* After M_COLLECT_ERRORS_SLOWLY_AFTER different errors have
742 been found, be much more conservative about collecting new
743 ones. */
744 if (n_errs_shown >= M_COLLECT_ERRORS_SLOWLY_AFTER
745 && !VG_(clo_xml)) {
746 exe_res = Vg_LowRes;
747 if (!slowdown_message) {
748 VG_(umsg)("\n");
749 VG_(umsg)("More than %d errors detected. Subsequent errors\n",
750 M_COLLECT_ERRORS_SLOWLY_AFTER);
751 VG_(umsg)("will still be recorded, but in less "
752 "detail than before.\n");
753 slowdown_message = True;
754 }
755 }
756
757 /* Build ourselves the error */
758 construct_error ( &err, tid, ekind, a, s, extra, NULL );
759
760 /* First, see if we've got an error record matching this one. */
761 em_errlist_searches++;
762 p = errors;
763 p_prev = NULL;
764 while (p != NULL) {
765 em_errlist_cmps++;
766 if (eq_Error(exe_res, p, &err)) {
767 /* Found it. */
768 p->count++;
769 if (p->supp != NULL) {
770 /* Deal correctly with suppressed errors. */
771 p->supp->count++;
772 n_errs_suppressed++;
773 } else {
774 n_errs_found++;
775 }
776
777 /* Move p to the front of the list so that future searches
778 for it are faster. It also allows to print the last
779 error (see VG_(show_last_error). */
780 if (p_prev != NULL) {
781 vg_assert(p_prev->next == p);
782 p_prev->next = p->next;
783 p->next = errors;
784 errors = p;
785 }
786
787 return;
788 }
789 p_prev = p;
790 p = p->next;
791 }
792
793 /* Didn't see it. Copy and add. */
794
795 /* OK, we're really going to collect it. The context is on the stack and
796 will disappear shortly, so we must copy it. First do the main
797 (non-'extra') part.
798
799 Then VG_(tdict).tool_update_extra can update the 'extra' part. This
800 is for when there are more details to fill in which take time to work
801 out but don't affect our earlier decision to include the error -- by
802 postponing those details until now, we avoid the extra work in the
803 case where we ignore the error. Ugly.
804
805 Then, if there is an 'extra' part, copy it too, using the size that
806 VG_(tdict).tool_update_extra returned. Also allow for people using
807 the void* extra field for a scalar value like an integer.
808 */
809
810 /* copy main part */
811 p = VG_(malloc)("errormgr.mre.1", sizeof(Error));
812 *p = err;
813
814 /* update 'extra' */
815 switch (ekind) {
816 //(example code, see comment on CoreSuppKind above)
817 //case ThreadErr:
818 // vg_assert(VG_(needs).core_errors);
819 // extra_size = <something>
820 // break;
821 default:
822 vg_assert(VG_(needs).tool_errors);
823 extra_size = VG_TDICT_CALL(tool_update_extra, p);
824 break;
825 }
826
827 /* copy the error string, if there is one.
828 note: if we would have many errors with big strings, using a
829 DedupPoolAlloc for these strings will avoid duplicating
830 such string in each error using it. */
831 if (NULL != p->string) {
832 p->string = VG_(strdup)("errormgr.mre.2", p->string);
833 }
834
835 /* copy block pointed to by 'extra', if there is one */
836 if (NULL != p->extra && 0 != extra_size) {
837 void* new_extra = VG_(malloc)("errormgr.mre.3", extra_size);
838 VG_(memcpy)(new_extra, p->extra, extra_size);
839 p->extra = new_extra;
840 }
841
842 p->next = errors;
843 p->supp = is_suppressible_error(&err);
844 errors = p;
845 if (p->supp == NULL) {
846 /* update stats */
847 n_err_contexts++;
848 n_errs_found++;
849 n_errs_shown++;
850 /* Actually show the error; more complex than you might think. */
851 pp_Error( p, /*allow_db_attach*/True, VG_(clo_xml) );
852 } else {
853 n_supp_contexts++;
854 n_errs_suppressed++;
855 p->supp->count++;
856 }
857 }
858
859 /* Second top-level entry point to the error management subsystem, for
860 errors that the tool wants to report immediately, eg. because they're
861 guaranteed to only happen once. This avoids all the recording and
862 comparing stuff. But they can be suppressed; returns True if it is
863 suppressed. Bool 'print_error' dictates whether to print the error.
864 Bool 'count_error' dictates whether to count the error in n_errs_found.
865 */
VG_(unique_error)866 Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind, Addr a, const HChar* s,
867 void* extra, ExeContext* where, Bool print_error,
868 Bool allow_db_attach, Bool count_error )
869 {
870 Error err;
871 Supp *su;
872
873 /* Ignore it if error acquisition is disabled for this thread. */
874 ThreadState* tst = VG_(get_ThreadState)(tid);
875 if (tst->err_disablement_level > 0)
876 return False; /* ignored, not suppressed */
877
878 /* Build ourselves the error */
879 construct_error ( &err, tid, ekind, a, s, extra, where );
880
881 /* Unless it's suppressed, we're going to show it. Don't need to make
882 a copy, because it's only temporary anyway.
883
884 Then update the 'extra' part with VG_(tdict).tool_update_extra),
885 because that can have an affect on whether it's suppressed. Ignore
886 the size return value of VG_(tdict).tool_update_extra, because we're
887 not copying 'extra'. Similarly, 's' is also not copied. */
888 (void)VG_TDICT_CALL(tool_update_extra, &err);
889
890 su = is_suppressible_error(&err);
891 if (NULL == su) {
892 if (count_error) {
893 n_errs_found++;
894 n_err_contexts++;
895 }
896
897 if (print_error) {
898 /* update stats */
899 n_errs_shown++;
900 /* Actually show the error; more complex than you might think. */
901 pp_Error(&err, allow_db_attach, VG_(clo_xml));
902 }
903 return False;
904
905 } else {
906 if (count_error) {
907 n_errs_suppressed++;
908 n_supp_contexts++;
909 }
910 su->count++;
911 return True;
912 }
913 }
914
915
916 /*------------------------------------------------------------*/
917 /*--- Exported fns ---*/
918 /*------------------------------------------------------------*/
919
920 /* Show the used suppressions. Returns False if no suppression
921 got used. */
show_used_suppressions(void)922 static Bool show_used_suppressions ( void )
923 {
924 Supp *su;
925 Bool any_supp;
926
927 if (VG_(clo_xml))
928 VG_(printf_xml)("<suppcounts>\n");
929
930 any_supp = False;
931 for (su = suppressions; su != NULL; su = su->next) {
932 if (su->count <= 0)
933 continue;
934 if (VG_(clo_xml)) {
935 VG_(printf_xml)( " <pair>\n"
936 " <count>%d</count>\n"
937 " <name>%pS</name>\n"
938 " </pair>\n",
939 su->count, su->sname );
940 } else {
941 HChar *xtra = NULL;
942 Int xtra_size = 0;
943 SizeT num_written;
944 // blank line before the first shown suppression, if any
945 if (!any_supp)
946 VG_(dmsg)("\n");
947
948 do {
949 xtra_size += 256;
950 xtra = VG_(realloc)("errormgr.sus.1", xtra, xtra_size);
951 num_written = VG_TDICT_CALL(tool_print_extra_suppression_use,
952 su, xtra, xtra_size);
953 } while (num_written == xtra_size); // resize buffer and retry
954
955 // Ensure buffer is properly terminated
956 vg_assert(xtra[num_written] == '\0');
957
958 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
959 su->clo_suppressions_i);
960 VG_(dmsg)("used_suppression: %6d %s %s:%d%s%s\n", su->count, su->sname,
961 filename,
962 su->sname_lineno,
963 num_written ? " " : "", xtra);
964 VG_(free)(xtra);
965 }
966 any_supp = True;
967 }
968
969 if (VG_(clo_xml))
970 VG_(printf_xml)("</suppcounts>\n");
971
972 return any_supp;
973 }
974
975 /* Show all the errors that occurred, and possibly also the
976 suppressions used. */
VG_(show_all_errors)977 void VG_(show_all_errors) ( Int verbosity, Bool xml )
978 {
979 Int i, n_min;
980 Error *p, *p_min;
981 Bool any_supp;
982
983 if (verbosity == 0)
984 return;
985
986 /* If we're printing XML, just show the suppressions and stop. */
987 if (xml) {
988 (void)show_used_suppressions();
989 return;
990 }
991
992 /* We only get here if not printing XML. */
993 VG_(umsg)("ERROR SUMMARY: "
994 "%d errors from %d contexts (suppressed: %d from %d)\n",
995 n_errs_found, n_err_contexts,
996 n_errs_suppressed, n_supp_contexts );
997
998 if (verbosity <= 1)
999 return;
1000
1001 // We do the following only at -v or above, and only in non-XML
1002 // mode
1003
1004 /* Print the contexts in order of increasing error count.
1005 Once an error is shown, we add a huge value to its count to filter it
1006 out.
1007 After having shown all errors, we reset count to the original value. */
1008 for (i = 0; i < n_err_contexts; i++) {
1009 n_min = (1 << 30) - 1;
1010 p_min = NULL;
1011 for (p = errors; p != NULL; p = p->next) {
1012 if (p->supp != NULL) continue;
1013 if (p->count < n_min) {
1014 n_min = p->count;
1015 p_min = p;
1016 }
1017 }
1018 // XXX: this isn't right. See bug 203651.
1019 if (p_min == NULL) continue; //VG_(core_panic)("show_all_errors()");
1020
1021 VG_(umsg)("\n");
1022 VG_(umsg)("%d errors in context %d of %d:\n",
1023 p_min->count, i+1, n_err_contexts);
1024 pp_Error( p_min, False/*allow_db_attach*/, False /* xml */ );
1025
1026 // We're not printing XML -- we'd have exited above if so.
1027 vg_assert(! xml);
1028
1029 if ((i+1 == VG_(clo_dump_error))) {
1030 StackTrace ips = VG_(get_ExeContext_StackTrace)(p_min->where);
1031 VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to debugging*/,
1032 ips[0], /*debugging*/True, 0xFE/*verbosity*/,
1033 /*bbs_done*/0,
1034 /*allow redir?*/True);
1035 }
1036
1037 p_min->count = p_min->count + (1 << 30);
1038 }
1039
1040 /* reset the counts, otherwise a 2nd call does not show anything anymore */
1041 for (p = errors; p != NULL; p = p->next) {
1042 if (p->count >= (1 << 30))
1043 p->count = p->count - (1 << 30);
1044 }
1045
1046
1047 any_supp = show_used_suppressions();
1048
1049 if (any_supp)
1050 VG_(umsg)("\n");
1051 // reprint this, so users don't have to scroll way up to find
1052 // the first printing
1053 VG_(umsg)("ERROR SUMMARY: "
1054 "%d errors from %d contexts (suppressed: %d from %d)\n",
1055 n_errs_found, n_err_contexts, n_errs_suppressed,
1056 n_supp_contexts );
1057 }
1058
VG_(show_last_error)1059 void VG_(show_last_error) ( void )
1060 {
1061 if (n_err_contexts == 0) {
1062 VG_(umsg)("No errors yet\n");
1063 return;
1064 }
1065
1066 pp_Error( errors, False/*allow_db_attach*/, False/*xml*/ );
1067 }
1068
1069
1070 /* Show occurrence counts of all errors, in XML form. */
VG_(show_error_counts_as_XML)1071 void VG_(show_error_counts_as_XML) ( void )
1072 {
1073 Error* err;
1074 VG_(printf_xml)("<errorcounts>\n");
1075 for (err = errors; err != NULL; err = err->next) {
1076 if (err->supp != NULL)
1077 continue;
1078 if (err->count <= 0)
1079 continue;
1080 VG_(printf_xml)(" <pair>\n");
1081 VG_(printf_xml)(" <count>%d</count>\n", err->count);
1082 VG_(printf_xml)(" <unique>0x%x</unique>\n", err->unique);
1083 VG_(printf_xml)(" </pair>\n");
1084 }
1085 VG_(printf_xml)("</errorcounts>\n");
1086 VG_(printf_xml)("\n");
1087 }
1088
1089
1090 /*------------------------------------------------------------*/
1091 /*--- Suppression parsing ---*/
1092 /*------------------------------------------------------------*/
1093
1094 /* Get the next char from fd into *out_buf. Returns 1 if success,
1095 0 if eof or < 0 if error. */
1096
get_char(Int fd,HChar * out_buf)1097 static Int get_char ( Int fd, HChar* out_buf )
1098 {
1099 Int r;
1100 static HChar buf[256];
1101 static Int buf_size = 0;
1102 static Int buf_used = 0;
1103 vg_assert(buf_size >= 0 && buf_size <= sizeof buf);
1104 vg_assert(buf_used >= 0 && buf_used <= buf_size);
1105 if (buf_used == buf_size) {
1106 r = VG_(read)(fd, buf, sizeof buf);
1107 if (r < 0) return r; /* read failed */
1108 vg_assert(r >= 0 && r <= sizeof buf);
1109 buf_size = r;
1110 buf_used = 0;
1111 }
1112 if (buf_size == 0)
1113 return 0; /* eof */
1114 vg_assert(buf_size >= 0 && buf_size <= sizeof buf);
1115 vg_assert(buf_used >= 0 && buf_used < buf_size);
1116 *out_buf = buf[buf_used];
1117 buf_used++;
1118 return 1;
1119 }
1120
1121 // Get a non blank non comment line.
1122 // Returns True if eof.
get_nbnc_line(Int fd,HChar ** bufpp,SizeT * nBufp,Int * lineno)1123 static Bool get_nbnc_line ( Int fd, HChar** bufpp, SizeT* nBufp, Int* lineno )
1124 {
1125 HChar* buf = *bufpp;
1126 SizeT nBuf = *nBufp;
1127 HChar ch;
1128 Int n, i;
1129
1130 vg_assert(lineno); // lineno needed to correctly track line numbers.
1131
1132 while (True) {
1133 buf[0] = 0;
1134 /* First, read until a non-blank char appears. */
1135 while (True) {
1136 n = get_char(fd, &ch);
1137 if (n == 1 && !VG_(isspace)(ch)) break;
1138 if (n == 1 && ch == '\n')
1139 (*lineno)++;
1140 if (n <= 0) return True;
1141 }
1142
1143 /* Now, read the line into buf. */
1144 i = 0;
1145 buf[i++] = ch; buf[i] = 0;
1146 while (True) {
1147 n = get_char(fd, &ch);
1148 if (n <= 0) return False; /* the next call will return True */
1149 if (ch == '\n')
1150 (*lineno)++;
1151 if (ch == '\n') break;
1152 if (i > 0 && i == nBuf-1) {
1153 *nBufp = nBuf = nBuf * 2;
1154 #define RIDICULOUS 100000
1155 vg_assert2(nBuf < RIDICULOUS, // Just a sanity check, really.
1156 "VG_(get_line): line longer than %d chars, aborting\n",
1157 RIDICULOUS);
1158 *bufpp = buf = VG_(realloc)("errormgr.get_line.1", buf, nBuf);
1159 }
1160 buf[i++] = ch; buf[i] = 0;
1161 }
1162 while (i > 1 && VG_(isspace)(buf[i-1])) {
1163 i--; buf[i] = 0;
1164 };
1165
1166 // VG_(printf)("The line *%p %d is '%s'\n", lineno, *lineno, buf);
1167 /* Ok, we have a line. If a non-comment line, return.
1168 If a comment line, start all over again. */
1169 if (buf[0] != '#') return False;
1170 }
1171 }
1172
1173 // True if buf starts with fun: or obj: or is ...
is_location_line(const HChar * buf)1174 static Bool is_location_line (const HChar* buf)
1175 {
1176 return VG_(strncmp)(buf, "fun:", 4) == 0
1177 || VG_(strncmp)(buf, "obj:", 4) == 0
1178 || VG_(strcmp)(buf, "...") == 0;
1179 }
1180
VG_(get_line)1181 Bool VG_(get_line) ( Int fd, HChar** bufpp, SizeT* nBufp, Int* lineno )
1182 {
1183 Bool eof = get_nbnc_line (fd, bufpp, nBufp, lineno);
1184
1185 if (eof)
1186 return True;
1187
1188 if (is_location_line(*bufpp))
1189 return True; // Not a extra suppr line
1190 else
1191 return False; // A suppression extra line
1192 }
1193
1194 /* True if s contains no wildcard (?, *) characters. */
is_simple_str(const HChar * s)1195 static Bool is_simple_str (const HChar *s)
1196 {
1197 while (*s) {
1198 if (*s == '?' || *s == '*')
1199 return False;
1200 s++;
1201 }
1202 return True;
1203 }
1204
1205 /* buf contains the raw name of a caller, supposedly either
1206 fun:some_function_name or
1207 obj:some_object_name or
1208 ...
1209 Set p->ty and p->name accordingly.
1210 p->name is allocated and set to the string
1211 after the descriptor (fun: or obj:) part.
1212 Returns False if failed.
1213 */
setLocationTy(SuppLoc * p,const HChar * buf)1214 static Bool setLocationTy ( SuppLoc* p, const HChar *buf )
1215 {
1216 if (VG_(strncmp)(buf, "fun:", 4) == 0) {
1217 p->name = VG_(strdup)("errormgr.sLTy.1", buf+4);
1218 p->name_is_simple_str = is_simple_str (p->name);
1219 p->ty = FunName;
1220 return True;
1221 }
1222 if (VG_(strncmp)(buf, "obj:", 4) == 0) {
1223 p->name = VG_(strdup)("errormgr.sLTy.2", buf+4);
1224 p->name_is_simple_str = is_simple_str (p->name);
1225 p->ty = ObjName;
1226 return True;
1227 }
1228 if (VG_(strcmp)(buf, "...") == 0) {
1229 p->name = NULL;
1230 p->name_is_simple_str = False;
1231 p->ty = DotDotDot;
1232 return True;
1233 }
1234 VG_(printf)("location should be \"...\", or should start "
1235 "with \"fun:\" or \"obj:\"\n");
1236 return False;
1237 }
1238
1239
1240 /* Look for "tool" in a string like "tool1,tool2,tool3" */
tool_name_present(const HChar * name,const HChar * names)1241 static Bool tool_name_present(const HChar *name, const HChar *names)
1242 {
1243 Bool found;
1244 HChar *s = NULL; /* Shut gcc up */
1245 Int len = VG_(strlen)(name);
1246
1247 found = (NULL != (s = VG_(strstr)(names, name)) &&
1248 (s == names || *(s-1) == ',') &&
1249 (*(s+len) == ',' || *(s+len) == '\0')
1250 );
1251
1252 return found;
1253 }
1254
1255 /* Read suppressions from the file specified in
1256 VG_(clo_suppressions)[clo_suppressions_i]
1257 and place them in the suppressions list. If there's any difficulty
1258 doing this, just give up -- there's no point in trying to recover.
1259 */
load_one_suppressions_file(Int clo_suppressions_i)1260 static void load_one_suppressions_file ( Int clo_suppressions_i )
1261 {
1262 const HChar* filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1263 clo_suppressions_i);
1264 SysRes sres;
1265 Int fd, i, j, lineno = 0;
1266 Bool got_a_location_line_read_by_tool;
1267 Bool eof;
1268 SizeT nBuf = 200;
1269 HChar* buf = VG_(malloc)("errormgr.losf.1", nBuf);
1270 HChar* tool_names;
1271 HChar* supp_name;
1272 const HChar* err_str = NULL;
1273 SuppLoc tmp_callers[VG_MAX_SUPP_CALLERS];
1274
1275 // Check it's not a directory.
1276 if (VG_(is_dir)( filename )) {
1277 if (VG_(clo_xml))
1278 VG_(printf_xml)("</valgrindoutput>\n");
1279 VG_(umsg)("FATAL: suppressions file \"%s\" is a directory\n", filename );
1280 VG_(exit)(1);
1281 }
1282
1283 // Open the suppression file.
1284 sres = VG_(open)( filename, VKI_O_RDONLY, 0 );
1285 if (sr_isError(sres)) {
1286 if (VG_(clo_xml))
1287 VG_(printf_xml)("</valgrindoutput>\n");
1288 VG_(umsg)("FATAL: can't open suppressions file \"%s\"\n", filename );
1289 VG_(exit)(1);
1290 }
1291 fd = sr_Res(sres);
1292
1293 # define BOMB(S) { err_str = S; goto syntax_error; }
1294
1295 while (True) {
1296 /* Assign and initialise the two suppression halves (core and tool) */
1297 Supp* supp;
1298 supp = VG_(malloc)("errormgr.losf.1", sizeof(Supp));
1299 supp->count = 0;
1300
1301 // Initialise temporary reading-in buffer.
1302 for (i = 0; i < VG_MAX_SUPP_CALLERS; i++) {
1303 tmp_callers[i].ty = NoName;
1304 tmp_callers[i].name_is_simple_str = False;
1305 tmp_callers[i].name = NULL;
1306 }
1307
1308 supp->string = supp->extra = NULL;
1309
1310 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1311 if (eof) {
1312 VG_(free)(supp);
1313 break;
1314 }
1315
1316 if (!VG_STREQ(buf, "{")) BOMB("expected '{' or end-of-file");
1317
1318 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1319
1320 if (eof || VG_STREQ(buf, "}")) BOMB("unexpected '}'");
1321
1322 supp->sname = VG_(strdup)("errormgr.losf.2", buf);
1323 supp->clo_suppressions_i = clo_suppressions_i;
1324 supp->sname_lineno = lineno;
1325
1326 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1327
1328 if (eof) BOMB("unexpected end-of-file (expecting tool:suppr)");
1329
1330 /* Check it has the "tool1,tool2,...:supp" form (look for ':') */
1331 i = 0;
1332 while (True) {
1333 if (buf[i] == ':') break;
1334 if (buf[i] == '\0') BOMB("malformed 'tool1,tool2,...:supp' line");
1335 i++;
1336 }
1337 buf[i] = '\0'; /* Replace ':', splitting into two strings */
1338
1339 tool_names = & buf[0];
1340 supp_name = & buf[i+1];
1341
1342 if (VG_(needs).core_errors && tool_name_present("core", tool_names))
1343 {
1344 // A core suppression
1345 //(example code, see comment on CoreSuppKind above)
1346 //if (VG_STREQ(supp_name, "Thread"))
1347 // supp->skind = ThreadSupp;
1348 //else
1349 BOMB("unknown core suppression type");
1350 }
1351 else if (VG_(needs).tool_errors &&
1352 tool_name_present(VG_(details).name, tool_names))
1353 {
1354 // A tool suppression
1355 if (VG_TDICT_CALL(tool_recognised_suppression, supp_name, supp)) {
1356 /* Do nothing, function fills in supp->skind */
1357 } else {
1358 BOMB("unknown tool suppression type");
1359 }
1360 }
1361 else {
1362 // Ignore rest of suppression
1363 while (True) {
1364 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1365 if (eof) BOMB("unexpected end-of-file (when skipping suppression)");
1366 if (VG_STREQ(buf, "}"))
1367 break;
1368 }
1369 VG_(free)(supp->sname);
1370 VG_(free)(supp);
1371 continue;
1372 }
1373
1374 buf[0] = 0;
1375 // tool_read_extra_suppression_info might read lines
1376 // from fd till a location line.
1377 if (VG_(needs).tool_errors &&
1378 !VG_TDICT_CALL(tool_read_extra_suppression_info,
1379 fd, &buf, &nBuf, &lineno, supp))
1380 {
1381 BOMB("bad or missing extra suppression info");
1382 }
1383
1384 got_a_location_line_read_by_tool = buf[0] != 0 && is_location_line(buf);
1385
1386 /* the main frame-descriptor reading loop */
1387 i = 0;
1388 while (True) {
1389 if (got_a_location_line_read_by_tool) {
1390 got_a_location_line_read_by_tool = False;
1391 eof = False;
1392 } else {
1393 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1394 }
1395 if (eof)
1396 BOMB("unexpected end-of-file (when reading stack trace)");
1397 if (VG_STREQ(buf, "}")) {
1398 if (i > 0) {
1399 break;
1400 } else {
1401 BOMB("missing stack trace");
1402 }
1403 }
1404 if (i == VG_MAX_SUPP_CALLERS)
1405 BOMB("too many callers in stack trace");
1406 if (i > 0 && i >= VG_(clo_backtrace_size))
1407 break;
1408 if (!setLocationTy(&(tmp_callers[i]), buf))
1409 BOMB("location should be \"...\", or should start "
1410 "with \"fun:\" or \"obj:\"");
1411 i++;
1412 }
1413
1414 // If the num callers is >= VG_(clo_backtrace_size), ignore any extra
1415 // lines and grab the '}'.
1416 if (!VG_STREQ(buf, "}")) {
1417 do {
1418 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1419 } while (!eof && !VG_STREQ(buf, "}"));
1420 }
1421
1422 // Reject entries which are entirely composed of frame
1423 // level wildcards.
1424 vg_assert(i > 0); // guaranteed by frame-descriptor reading loop
1425 for (j = 0; j < i; j++) {
1426 if (tmp_callers[j].ty == FunName || tmp_callers[j].ty == ObjName)
1427 break;
1428 vg_assert(tmp_callers[j].ty == DotDotDot);
1429 }
1430 vg_assert(j >= 0 && j <= i);
1431 if (j == i) {
1432 // we didn't find any non-"..." entries
1433 BOMB("suppression must contain at least one location "
1434 "line which is not \"...\"");
1435 }
1436
1437 // Copy tmp_callers[] into supp->callers[]
1438 supp->n_callers = i;
1439 supp->callers = VG_(malloc)("errormgr.losf.4", i * sizeof(SuppLoc));
1440 for (i = 0; i < supp->n_callers; i++) {
1441 supp->callers[i] = tmp_callers[i];
1442 }
1443
1444 supp->next = suppressions;
1445 suppressions = supp;
1446 }
1447 VG_(free)(buf);
1448 VG_(close)(fd);
1449 return;
1450
1451 syntax_error:
1452 if (VG_(clo_xml))
1453 VG_(printf_xml)("</valgrindoutput>\n");
1454 VG_(umsg)("FATAL: in suppressions file \"%s\" near line %d:\n",
1455 filename, lineno );
1456 VG_(umsg)(" %s\n", err_str );
1457
1458 VG_(close)(fd);
1459 VG_(umsg)("exiting now.\n");
1460 VG_(exit)(1);
1461
1462 # undef BOMB
1463 }
1464
1465
VG_(load_suppressions)1466 void VG_(load_suppressions) ( void )
1467 {
1468 Int i;
1469 suppressions = NULL;
1470 for (i = 0; i < VG_(sizeXA)(VG_(clo_suppressions)); i++) {
1471 if (VG_(clo_verbosity) > 1) {
1472 VG_(dmsg)("Reading suppressions file: %s\n",
1473 *(HChar**) VG_(indexXA)(VG_(clo_suppressions), i));
1474 }
1475 load_one_suppressions_file( i );
1476 }
1477 }
1478
1479
1480 /*------------------------------------------------------------*/
1481 /*--- Matching errors to suppressions ---*/
1482 /*------------------------------------------------------------*/
1483
1484 /* Parameterising functions for the use of VG_(generic_match) in
1485 suppression-vs-error matching. The suppression frames (SuppLoc)
1486 play the role of 'pattern'-element, and the error frames (IPs,
1487 hence simply Addrs) play the role of 'input'. In short then, we're
1488 matching a sequence of Addrs against a pattern composed of a
1489 sequence of SuppLocs.
1490 */
supploc_IsStar(const void * supplocV)1491 static Bool supploc_IsStar ( const void* supplocV )
1492 {
1493 const SuppLoc* supploc = supplocV;
1494 return supploc->ty == DotDotDot;
1495 }
1496
supploc_IsQuery(const void * supplocV)1497 static Bool supploc_IsQuery ( const void* supplocV )
1498 {
1499 return False; /* there's no '?' equivalent in the supp syntax */
1500 }
1501
1502 /* IPtoFunOrObjCompleter is a lazy completer of the IPs
1503 needed to match an error with the suppression patterns.
1504 The matching between an IP and a suppression pattern is done either
1505 with the IP function name or with the IP object name.
1506 First time the fun or obj name is needed for an IP member
1507 of a stack trace, it will be computed and stored in names.
1508 Also, if the IP corresponds to one or more inlined function calls,
1509 the inlined function names are expanded.
1510 The IPtoFunOrObjCompleter type is designed to minimise the nr of
1511 allocations and the nr of debuginfo search. */
1512 typedef
1513 struct {
1514 StackTrace ips; // stack trace we are lazily completing.
1515 UWord n_ips; // nr of elements in ips.
1516
1517 // VG_(generic_match) calls haveInputInpC to check
1518 // for the presence of an input element identified by ixInput
1519 // (i.e. a number that identifies the ixInput element of the
1520 // input sequence). It calls supp_pattEQinp to match this input
1521 // element with a pattern.
1522 // When inlining info is used to provide inlined function calls
1523 // in stacktraces, one IP in ips can be expanded in several
1524 // function names. So, each time input (or presence of input)
1525 // is requested by VG_(generic_match), we will expand
1526 // more IP of ips till we have expanded enough to reach the
1527 // input element requested (or we cannot expand anymore).
1528
1529 UWord n_ips_expanded;
1530 // n_ips_expanded maintains the nr of elements in ips that we have
1531 // already expanded.
1532 UWord n_expanded;
1533 // n_expanded maintains the nr of elements resulting from the expansion
1534 // of the n_ips_expanded IPs. Without inlined function calls,
1535 // n_expanded == n_ips_expanded. With inlining info,
1536 // n_expanded >= n_ips_expanded.
1537
1538 Int* n_offsets_per_ip;
1539 // n_offsets_per_ip[i] gives the nr of offsets in fun_offsets and
1540 // obj_offsets resulting of the expansion of ips[i].
1541 // The sum of all n_expanded_per_ip must be equal to n_expanded.
1542 // This array allows to retrieve the position in ips corresponding to
1543 // an ixInput.
1544
1545 // size (in elements) of fun_offsets and obj_offsets.
1546 // (fun|obj)_offsets are reallocated if more space is needed
1547 // to expand an IP.
1548 UWord sz_offsets;
1549
1550 Int* fun_offsets;
1551 // fun_offsets[ixInput] is the offset in names where the
1552 // function name for the ixInput element of the input sequence
1553 // can be found. As one IP of ips can be expanded in several
1554 // function calls due to inlined function calls, we can have more
1555 // elements in fun_offsets than in ips.
1556 // An offset -1 means the function name has not yet been computed.
1557 Int* obj_offsets;
1558 // Similarly, obj_offsets[ixInput] gives the offset for the
1559 // object name for ips[ixInput]
1560 // (-1 meaning object name not yet been computed).
1561
1562 // All function names and object names will be concatenated
1563 // in names. names is reallocated on demand.
1564 HChar *names;
1565 Int names_szB; // size of names.
1566 Int names_free; // offset first free HChar in names.
1567 }
1568 IPtoFunOrObjCompleter;
1569
pp_ip2fo(const IPtoFunOrObjCompleter * ip2fo)1570 static void pp_ip2fo (const IPtoFunOrObjCompleter* ip2fo)
1571 {
1572 Int i, j;
1573 Int o;
1574
1575 VG_(printf)("n_ips %lu n_ips_expanded %lu resulting in n_expanded %lu\n",
1576 ip2fo->n_ips, ip2fo->n_ips_expanded, ip2fo->n_expanded);
1577 for (i = 0; i < ip2fo->n_ips_expanded; i++) {
1578 o = 0;
1579 for (j = 0; j < i; j++)
1580 o += ip2fo->n_offsets_per_ip[j];
1581 VG_(printf)("ips %d 0x08%lx offset [%d,%d] ",
1582 i, ip2fo->ips[i],
1583 o, o+ip2fo->n_offsets_per_ip[i]-1);
1584 for (j = 0; j < ip2fo->n_offsets_per_ip[i]; j++) {
1585 VG_(printf)("%sfun:%s obj:%s\n",
1586 j == 0 ? "" : " ",
1587 ip2fo->fun_offsets[o+j] == -1 ?
1588 "<not expanded>" : &ip2fo->names[ip2fo->fun_offsets[o+j]],
1589 ip2fo->obj_offsets[o+j] == -1 ?
1590 "<not expanded>" : &ip2fo->names[ip2fo->obj_offsets[o+j]]);
1591 }
1592 }
1593 }
1594
1595 /* free the memory in ip2fo.
1596 At debuglog 4, su (or NULL) will be used to show the matching
1597 (or non matching) with ip2fo. */
clearIPtoFunOrObjCompleter(const Supp * su,IPtoFunOrObjCompleter * ip2fo)1598 static void clearIPtoFunOrObjCompleter ( const Supp *su,
1599 IPtoFunOrObjCompleter* ip2fo)
1600 {
1601 if (DEBUG_ERRORMGR || VG_(debugLog_getLevel)() >= 4) {
1602 if (su) {
1603 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1604 su->clo_suppressions_i);
1605 VG_(dmsg)("errormgr matching end suppression %s %s:%d matched:\n",
1606 su->sname,
1607 filename,
1608 su->sname_lineno);
1609 } else
1610 VG_(dmsg)("errormgr matching end no suppression matched:\n");
1611 VG_(pp_StackTrace) (ip2fo->ips, ip2fo->n_ips);
1612 pp_ip2fo(ip2fo);
1613 }
1614 if (ip2fo->n_offsets_per_ip) VG_(free)(ip2fo->n_offsets_per_ip);
1615 if (ip2fo->fun_offsets) VG_(free)(ip2fo->fun_offsets);
1616 if (ip2fo->obj_offsets) VG_(free)(ip2fo->obj_offsets);
1617 if (ip2fo->names) VG_(free)(ip2fo->names);
1618 }
1619
1620 /* Grow ip2fo->names to ensure we have NEEDED characters available
1621 in ip2fo->names and returns a pointer to the first free char. */
grow_names(IPtoFunOrObjCompleter * ip2fo,SizeT needed)1622 static HChar* grow_names(IPtoFunOrObjCompleter* ip2fo, SizeT needed)
1623 {
1624 if (ip2fo->names_szB
1625 < ip2fo->names_free + needed) {
1626 if (needed < ERRTXT_LEN) needed = ERRTXT_LEN;
1627
1628 ip2fo->names
1629 = VG_(realloc)("foc_names",
1630 ip2fo->names,
1631 ip2fo->names_szB + needed);
1632 ip2fo->names_szB += needed;
1633 }
1634 return ip2fo->names + ip2fo->names_free;
1635 }
1636
1637 /* foComplete returns the function name or object name for ixInput.
1638 If needFun, returns the function name for this input
1639 else returns the object name for this input.
1640 The function name or object name will be computed and added in
1641 names if not yet done. */
foComplete(IPtoFunOrObjCompleter * ip2fo,Int ixInput,Bool needFun)1642 static HChar* foComplete(IPtoFunOrObjCompleter* ip2fo,
1643 Int ixInput, Bool needFun)
1644 {
1645 vg_assert (ixInput < ip2fo->n_expanded);
1646 vg_assert (VG_(clo_read_inline_info) || ixInput < ip2fo->n_ips);
1647
1648 // ptr to the offset array for function offsets (if needFun)
1649 // or object offsets (if !needFun).
1650 Int** offsets;
1651 if (needFun)
1652 offsets = &ip2fo->fun_offsets;
1653 else
1654 offsets = &ip2fo->obj_offsets;
1655
1656 // Complete Fun name or Obj name for IP if not yet done.
1657 if ((*offsets)[ixInput] == -1) {
1658 const HChar* caller;
1659
1660 (*offsets)[ixInput] = ip2fo->names_free;
1661 if (DEBUG_ERRORMGR) VG_(printf)("marking %s ixInput %d offset %d\n",
1662 needFun ? "fun" : "obj",
1663 ixInput, ip2fo->names_free);
1664 if (needFun) {
1665 // With inline info, fn names must have been completed already.
1666 vg_assert (!VG_(clo_read_inline_info));
1667 /* Get the function name into 'caller_name', or "???"
1668 if unknown. */
1669 // Nb: C++-mangled names are used in suppressions. Do, though,
1670 // Z-demangle them, since otherwise it's possible to wind
1671 // up comparing "malloc" in the suppression against
1672 // "_vgrZU_libcZdsoZa_malloc" in the backtrace, and the
1673 // two of them need to be made to match.
1674 if (!VG_(get_fnname_no_cxx_demangle)(ip2fo->ips[ixInput],
1675 &caller,
1676 NULL))
1677 caller = "???";
1678 } else {
1679 /* Get the object name into 'caller_name', or "???"
1680 if unknown. */
1681 UWord i;
1682 UWord last_expand_pos_ips = 0;
1683 UWord pos_ips;
1684
1685 /* First get the pos in ips corresponding to ixInput */
1686 for (pos_ips = 0; pos_ips < ip2fo->n_expanded; pos_ips++) {
1687 last_expand_pos_ips += ip2fo->n_offsets_per_ip[pos_ips];
1688 if (ixInput < last_expand_pos_ips)
1689 break;
1690 }
1691 /* pos_ips is the position in ips corresponding to ixInput.
1692 last_expand_pos_ips is the last offset in fun/obj where
1693 ips[pos_ips] has been expanded. */
1694
1695 if (!VG_(get_objname)(ip2fo->ips[pos_ips], &caller))
1696 caller = "???";
1697
1698 // Have all inlined calls pointing at this object name
1699 for (i = last_expand_pos_ips - ip2fo->n_offsets_per_ip[pos_ips] + 1;
1700 i < last_expand_pos_ips;
1701 i++) {
1702 ip2fo->obj_offsets[i] = ip2fo->names_free;
1703 if (DEBUG_ERRORMGR)
1704 VG_(printf) (" set obj_offset %lu to %d\n",
1705 i, ip2fo->names_free);
1706 }
1707 }
1708 SizeT caller_len = VG_(strlen)(caller);
1709 HChar* caller_name = grow_names(ip2fo, caller_len + 1);
1710 VG_(strcpy)(caller_name, caller);
1711 ip2fo->names_free += caller_len + 1;
1712 if (DEBUG_ERRORMGR) pp_ip2fo(ip2fo);
1713 }
1714
1715 return ip2fo->names + (*offsets)[ixInput];
1716 }
1717
1718 // Grow fun and obj _offsets arrays to have at least n_req elements.
1719 // Ensure n_offsets_per_ip is allocated.
grow_offsets(IPtoFunOrObjCompleter * ip2fo,Int n_req)1720 static void grow_offsets(IPtoFunOrObjCompleter* ip2fo, Int n_req)
1721 {
1722 Int i;
1723
1724 // n_offsets_per_ip must always have the size of the ips array
1725 if (ip2fo->n_offsets_per_ip == NULL) {
1726 ip2fo->n_offsets_per_ip = VG_(malloc)("grow_offsets",
1727 ip2fo->n_ips * sizeof(Int));
1728 for (i = 0; i < ip2fo->n_ips; i++)
1729 ip2fo->n_offsets_per_ip[i] = 0;
1730 }
1731
1732 if (ip2fo->sz_offsets >= n_req)
1733 return;
1734
1735 // Avoid too much re-allocation by allocating at least ip2fo->n_ips
1736 // elements and at least a few more elements than the current size.
1737 if (n_req < ip2fo->n_ips)
1738 n_req = ip2fo->n_ips;
1739 if (n_req < ip2fo->sz_offsets + 5)
1740 n_req = ip2fo->sz_offsets + 5;
1741
1742 ip2fo->fun_offsets = VG_(realloc)("grow_offsets", ip2fo->fun_offsets,
1743 n_req * sizeof(Int));
1744 for (i = ip2fo->sz_offsets; i < n_req; i++)
1745 ip2fo->fun_offsets[i] = -1;
1746
1747 ip2fo->obj_offsets = VG_(realloc)("grow_offsets", ip2fo->obj_offsets,
1748 n_req * sizeof(Int));
1749 for (i = ip2fo->sz_offsets; i < n_req; i++)
1750 ip2fo->obj_offsets[i] = -1;
1751
1752 ip2fo->sz_offsets = n_req;
1753 }
1754
1755 // Expands more IPs from ip2fo->ips.
expandInput(IPtoFunOrObjCompleter * ip2fo,UWord ixInput)1756 static void expandInput (IPtoFunOrObjCompleter* ip2fo, UWord ixInput )
1757 {
1758 while (ip2fo->n_ips_expanded < ip2fo->n_ips
1759 && ip2fo->n_expanded <= ixInput) {
1760 if (VG_(clo_read_inline_info)) {
1761 // Expand one more IP in one or more calls.
1762 const Addr IP = ip2fo->ips[ip2fo->n_ips_expanded];
1763 InlIPCursor *iipc;
1764
1765 iipc = VG_(new_IIPC)(IP);
1766 // The only thing we really need is the nr of inlined fn calls
1767 // corresponding to the IP we will expand.
1768 // However, computing this is mostly the same as finding
1769 // the function name. So, let's directly complete the function name.
1770 do {
1771 const HChar *caller;
1772 grow_offsets(ip2fo, ip2fo->n_expanded+1);
1773 ip2fo->fun_offsets[ip2fo->n_expanded] = ip2fo->names_free;
1774 if (!VG_(get_fnname_no_cxx_demangle)(IP,
1775 &caller,
1776 iipc))
1777 caller = "???";
1778 SizeT caller_len = VG_(strlen)(caller);
1779 HChar* caller_name = grow_names(ip2fo, caller_len + 1);
1780 VG_(strcpy)(caller_name, caller);
1781 ip2fo->names_free += caller_len + 1;
1782 ip2fo->n_expanded++;
1783 ip2fo->n_offsets_per_ip[ip2fo->n_ips_expanded]++;
1784 } while (VG_(next_IIPC)(iipc));
1785 ip2fo->n_ips_expanded++;
1786 VG_(delete_IIPC) (iipc);
1787 } else {
1788 // Without inlined fn call info, expansion simply
1789 // consists in allocating enough elements in (fun|obj)_offsets.
1790 // The function or object names themselves will be completed
1791 // when requested.
1792 Int i;
1793 grow_offsets(ip2fo, ip2fo->n_ips);
1794 ip2fo->n_ips_expanded = ip2fo->n_ips;
1795 ip2fo->n_expanded = ip2fo->n_ips;
1796 for (i = 0; i < ip2fo->n_ips; i++)
1797 ip2fo->n_offsets_per_ip[i] = 1;
1798 }
1799 }
1800 }
1801
haveInputInpC(void * inputCompleter,UWord ixInput)1802 static Bool haveInputInpC (void* inputCompleter, UWord ixInput )
1803 {
1804 IPtoFunOrObjCompleter* ip2fo = inputCompleter;
1805 expandInput(ip2fo, ixInput);
1806 return ixInput < ip2fo->n_expanded;
1807 }
1808
supp_pattEQinp(const void * supplocV,const void * addrV,void * inputCompleter,UWord ixInput)1809 static Bool supp_pattEQinp ( const void* supplocV, const void* addrV,
1810 void* inputCompleter, UWord ixInput )
1811 {
1812 const SuppLoc* supploc = supplocV; /* PATTERN */
1813 IPtoFunOrObjCompleter* ip2fo = inputCompleter;
1814 HChar* funobj_name; // Fun or Obj name.
1815 Bool ret;
1816
1817 expandInput(ip2fo, ixInput);
1818 vg_assert(ixInput < ip2fo->n_expanded);
1819
1820 /* So, does this IP address match this suppression-line? */
1821 switch (supploc->ty) {
1822 case DotDotDot:
1823 /* supp_pattEQinp is a callback from VG_(generic_match). As
1824 per the spec thereof (see include/pub_tool_seqmatch.h), we
1825 should never get called with a pattern value for which the
1826 _IsStar or _IsQuery function would return True. Hence
1827 this can't happen. */
1828 vg_assert(0);
1829 case ObjName:
1830 funobj_name = foComplete(ip2fo, ixInput, False /*needFun*/);
1831 break;
1832 case FunName:
1833 funobj_name = foComplete(ip2fo, ixInput, True /*needFun*/);
1834 break;
1835 default:
1836 vg_assert(0);
1837 }
1838
1839 /* So now we have the function or object name in funobj_name, and
1840 the pattern (at the character level) to match against is in
1841 supploc->name. Hence (and leading to a re-entrant call of
1842 VG_(generic_match) if there is a wildcard character): */
1843 if (supploc->name_is_simple_str)
1844 ret = VG_(strcmp) (supploc->name, funobj_name) == 0;
1845 else
1846 ret = VG_(string_match)(supploc->name, funobj_name);
1847 if (DEBUG_ERRORMGR)
1848 VG_(printf) ("supp_pattEQinp %s patt %s ixUnput %lu value:%s match:%s\n",
1849 supploc->ty == FunName ? "fun" : "obj",
1850 supploc->name, ixInput, funobj_name,
1851 ret ? "yes" : "no");
1852 return ret;
1853 }
1854
1855 /////////////////////////////////////////////////////
1856
supp_matches_callers(IPtoFunOrObjCompleter * ip2fo,const Supp * su)1857 static Bool supp_matches_callers(IPtoFunOrObjCompleter* ip2fo,
1858 const Supp* su)
1859 {
1860 /* Unwrap the args and set up the correct parameterisation of
1861 VG_(generic_match), using supploc_IsStar, supploc_IsQuery and
1862 supp_pattEQinp. */
1863 /* note, StackTrace ip2fo->ips === Addr* */
1864 SuppLoc* supps = su->callers;
1865 UWord n_supps = su->n_callers;
1866 UWord szbPatt = sizeof(SuppLoc);
1867 Bool matchAll = False; /* we just want to match a prefix */
1868 if (DEBUG_ERRORMGR) {
1869 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1870 su->clo_suppressions_i);
1871 VG_(dmsg)(" errormgr Checking match with %s %s:%d\n",
1872 su->sname,
1873 filename,
1874 su->sname_lineno);
1875 }
1876 return
1877 VG_(generic_match)(
1878 matchAll,
1879 /*PATT*/supps, szbPatt, n_supps, 0/*initial ixPatt*/,
1880 /*INPUT*/
1881 NULL, 0, 0, /* input/szbInput/nInput 0, as using an inputCompleter */
1882 0/*initial ixInput*/,
1883 supploc_IsStar, supploc_IsQuery, supp_pattEQinp,
1884 ip2fo, haveInputInpC
1885 );
1886 }
1887
1888 /////////////////////////////////////////////////////
1889
1890 static
supp_matches_error(const Supp * su,const Error * err)1891 Bool supp_matches_error(const Supp* su, const Error* err)
1892 {
1893 switch (su->skind) {
1894 //(example code, see comment on CoreSuppKind above)
1895 //case ThreadSupp:
1896 // return (err->ekind == ThreadErr);
1897 default:
1898 if (VG_(needs).tool_errors) {
1899 return VG_TDICT_CALL(tool_error_matches_suppression, err, su);
1900 } else {
1901 VG_(printf)(
1902 "\nUnhandled suppression type: %u. VG_(needs).tool_errors\n"
1903 "probably needs to be set.\n",
1904 err->ekind);
1905 VG_(core_panic)("unhandled suppression type");
1906 }
1907 }
1908 }
1909
1910 /////////////////////////////////////////////////////
1911
1912 /* Does an error context match a suppression? ie is this a suppressible
1913 error? If so, return a pointer to the Supp record, otherwise NULL.
1914 Tries to minimise the number of symbol searches since they are expensive.
1915 */
is_suppressible_error(const Error * err)1916 static Supp* is_suppressible_error ( const Error* err )
1917 {
1918 Supp* su;
1919 Supp* su_prev;
1920
1921 IPtoFunOrObjCompleter ip2fo;
1922 /* Conceptually, ip2fo contains an array of function names and an array of
1923 object names, corresponding to the array of IP of err->where.
1924 These names are just computed 'on demand' (so once maximum),
1925 then stored (efficiently, avoiding too many allocs) in ip2fo to be
1926 re-usable for the matching of the same IP with the next suppression
1927 pattern.
1928
1929 VG_(generic_match) gets this 'IP to Fun or Obj name completer' as one
1930 of its arguments. It will then pass it to the function
1931 supp_pattEQinp which will then lazily complete the IP function name or
1932 object name inside ip2fo. Next time the fun or obj name for the same
1933 IP is needed (i.e. for the matching with the next suppr pattern), then
1934 the fun or obj name will not be searched again in the debug info. */
1935
1936 /* stats gathering */
1937 em_supplist_searches++;
1938
1939 /* Prepare the lazy input completer. */
1940 ip2fo.ips = VG_(get_ExeContext_StackTrace)(err->where);
1941 ip2fo.n_ips = VG_(get_ExeContext_n_ips)(err->where);
1942 ip2fo.n_ips_expanded = 0;
1943 ip2fo.n_expanded = 0;
1944 ip2fo.sz_offsets = 0;
1945 ip2fo.n_offsets_per_ip = NULL;
1946 ip2fo.fun_offsets = NULL;
1947 ip2fo.obj_offsets = NULL;
1948 ip2fo.names = NULL;
1949 ip2fo.names_szB = 0;
1950 ip2fo.names_free = 0;
1951
1952 /* See if the error context matches any suppression. */
1953 if (DEBUG_ERRORMGR || VG_(debugLog_getLevel)() >= 4)
1954 VG_(dmsg)("errormgr matching begin\n");
1955 su_prev = NULL;
1956 for (su = suppressions; su != NULL; su = su->next) {
1957 em_supplist_cmps++;
1958 if (supp_matches_error(su, err)
1959 && supp_matches_callers(&ip2fo, su)) {
1960 /* got a match. */
1961 /* Inform the tool that err is suppressed by su. */
1962 (void)VG_TDICT_CALL(tool_update_extra_suppression_use, err, su);
1963 /* Move this entry to the head of the list
1964 in the hope of making future searches cheaper. */
1965 if (su_prev) {
1966 vg_assert(su_prev->next == su);
1967 su_prev->next = su->next;
1968 su->next = suppressions;
1969 suppressions = su;
1970 }
1971 clearIPtoFunOrObjCompleter(su, &ip2fo);
1972 return su;
1973 }
1974 su_prev = su;
1975 }
1976 clearIPtoFunOrObjCompleter(NULL, &ip2fo);
1977 return NULL; /* no matches */
1978 }
1979
1980 /* Show accumulated error-list and suppression-list search stats.
1981 */
VG_(print_errormgr_stats)1982 void VG_(print_errormgr_stats) ( void )
1983 {
1984 VG_(dmsg)(
1985 " errormgr: %'lu supplist searches, %'lu comparisons during search\n",
1986 em_supplist_searches, em_supplist_cmps
1987 );
1988 VG_(dmsg)(
1989 " errormgr: %'lu errlist searches, %'lu comparisons during search\n",
1990 em_errlist_searches, em_errlist_cmps
1991 );
1992 }
1993
1994 /*--------------------------------------------------------------------*/
1995 /*--- end ---*/
1996 /*--------------------------------------------------------------------*/
1997