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-2017 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_debuginfo.h"
35 #include "pub_core_debuglog.h"
36 #include "pub_core_errormgr.h"
37 #include "pub_core_execontext.h"
38 #include "pub_core_gdbserver.h"
39 #include "pub_core_libcbase.h"
40 #include "pub_core_libcassert.h"
41 #include "pub_core_libcfile.h"
42 #include "pub_core_libcprint.h"
43 #include "pub_core_libcproc.h" // For VG_(getpid)()
44 #include "pub_core_seqmatch.h"
45 #include "pub_core_mallocfree.h"
46 #include "pub_core_options.h"
47 #include "pub_core_stacktrace.h"
48 #include "pub_core_tooliface.h"
49 #include "pub_core_translate.h" // for VG_(translate)()
50 #include "pub_core_xarray.h" // VG_(xaprintf) et al
51
52 #define DEBUG_ERRORMGR 0 // set to 1 for heavyweight tracing
53
54 /*------------------------------------------------------------*/
55 /*--- Globals ---*/
56 /*------------------------------------------------------------*/
57
58 /* After this many different unsuppressed errors have been observed,
59 be more conservative about collecting new ones. */
60 #define M_COLLECT_ERRORS_SLOWLY_AFTER 100
61
62 /* After this many different unsuppressed errors have been observed,
63 stop collecting errors at all, and tell the user their program is
64 evidently a steaming pile of camel dung. */
65 #define M_COLLECT_NO_ERRORS_AFTER_SHOWN 1000
66
67 /* After this many total errors have been observed, stop collecting
68 errors at all. Counterpart to M_COLLECT_NO_ERRORS_AFTER_SHOWN. */
69 #define M_COLLECT_NO_ERRORS_AFTER_FOUND 10000000
70
71 /* The list of error contexts found, both suppressed and unsuppressed.
72 Initially empty, and grows as errors are detected. */
73 static Error* errors = NULL;
74
75 /* The list of suppression directives, as read from the specified
76 suppressions file. Note that the list gets rearranged as a result
77 of the searches done by is_suppressible_error(). */
78 static Supp* suppressions = NULL;
79
80 /* Running count of unsuppressed errors detected. */
81 static UInt n_errs_found = 0;
82
83 /* Running count of suppressed errors detected. */
84 static UInt n_errs_suppressed = 0;
85
86 /* Running count of errors shown. */
87 static UInt n_errs_shown = 0;
88
89 /* Running count of unsuppressed error contexts. */
90 static UInt n_err_contexts = 0;
91
92 /* Running count of suppressed error contexts. */
93 static UInt n_supp_contexts = 0;
94
95
96 /* forwards ... */
97 static Supp* is_suppressible_error ( const Error* err );
98
99 static ThreadId last_tid_printed = 1;
100
101 /* Stats: number of searches of the error list initiated. */
102 static UWord em_errlist_searches = 0;
103
104 /* Stats: number of comparisons done during error list
105 searching. */
106 static UWord em_errlist_cmps = 0;
107
108 /* Stats: number of searches of the suppression list initiated. */
109 static UWord em_supplist_searches = 0;
110
111 /* Stats: number of comparisons done during suppression list
112 searching. */
113 static UWord em_supplist_cmps = 0;
114
115 /*------------------------------------------------------------*/
116 /*--- Error type ---*/
117 /*------------------------------------------------------------*/
118
119 /* Errors. Extensible (via the 'extra' field). Tools can use a normal
120 enum (with element values in the normal range (0..)) for 'ekind'.
121 Functions for getting/setting the tool-relevant fields are in
122 include/pub_tool_errormgr.h.
123
124 When errors are found and recorded with VG_(maybe_record_error)(), all
125 the tool must do is pass in the four parameters; core will
126 allocate/initialise the error record.
127 */
128 struct _Error {
129 struct _Error* next;
130 // Unique tag. This gives the error a unique identity (handle) by
131 // which it can be referred to afterwords. Currently only used for
132 // XML printing.
133 UInt unique;
134 // NULL if unsuppressed; or ptr to suppression record.
135 Supp* supp;
136 Int count;
137
138 // The tool-specific part
139 ThreadId tid; // Initialised by core
140 ExeContext* where; // Initialised by core
141 ErrorKind ekind; // Used by ALL. Must be in the range (0..)
142 Addr addr; // Used frequently
143 const HChar* string; // Used frequently
144 void* extra; // For any tool-specific extras
145 };
146
147
VG_(get_error_where)148 ExeContext* VG_(get_error_where) ( const Error* err )
149 {
150 return err->where;
151 }
152
VG_(get_error_kind)153 ErrorKind VG_(get_error_kind) ( const Error* err )
154 {
155 return err->ekind;
156 }
157
VG_(get_error_address)158 Addr VG_(get_error_address) ( const Error* err )
159 {
160 return err->addr;
161 }
162
VG_(get_error_string)163 const HChar* VG_(get_error_string) ( const Error* err )
164 {
165 return err->string;
166 }
167
VG_(get_error_extra)168 void* VG_(get_error_extra) ( const Error* err )
169 {
170 return err->extra;
171 }
172
VG_(get_n_errs_found)173 UInt VG_(get_n_errs_found)( void )
174 {
175 return n_errs_found;
176 }
177
VG_(get_n_errs_shown)178 UInt VG_(get_n_errs_shown)( void )
179 {
180 return n_errs_shown;
181 }
182
183 /*------------------------------------------------------------*/
184 /*--- Suppression type ---*/
185 /*------------------------------------------------------------*/
186
187 /* Note: it is imperative this doesn't overlap with (0..) at all, as tools
188 * effectively extend it by defining their own enums in the (0..) range. */
189 typedef
190 enum {
191 // Nb: thread errors are a relic of the time when Valgrind's core
192 // could detect them. This example is left commented-out as an
193 // example should new core errors ever be added.
194 ThreadSupp = -1, /* Matches ThreadErr */
195 }
196 CoreSuppKind;
197
198 /* Max number of callers for context in a suppression is
199 VG_DEEPEST_BACKTRACE. */
200
201 /* For each caller specified for a suppression, record the nature of
202 the caller name. Not of interest to tools. */
203 typedef
204 enum {
205 NoName, /* Error case */
206 ObjName, /* Name is of an shared object file. */
207 FunName, /* Name is of a function. */
208 DotDotDot, /* Frame-level wildcard */
209 SrcName /* Name is of a src file. */
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 UInt lineno; /* Valid for SrcName. */
220 }
221 SuppLoc;
222
223 /* Suppressions. Tools can get/set tool-relevant parts with functions
224 declared in include/pub_tool_errormgr.h. Extensible via the 'extra' field.
225 Tools can use a normal enum (with element values in the normal range
226 (0..)) for 'skind'. */
227 struct _Supp {
228 struct _Supp* next;
229 Int count; // The number of times this error has been suppressed.
230 HChar* sname; // The name by which the suppression is referred to.
231
232 // Index in VG_(clo_suppressions) giving filename from which suppression
233 // was read, and the lineno in this file where sname was read.
234 Int clo_suppressions_i;
235 Int sname_lineno;
236
237 // Length of 'callers'
238 Int n_callers;
239 // Array of callers, for matching stack traces. First one (name of fn
240 // where err occurs) is mandatory; rest are optional.
241 SuppLoc* callers;
242
243 /* The tool-specific part */
244 SuppKind skind; // What kind of suppression. Must use the range (0..).
245 HChar* string; // String -- use is optional. NULL by default.
246 void* extra; // Anything else -- use is optional. NULL by default.
247 };
248
VG_(get_supp_kind)249 SuppKind VG_(get_supp_kind) ( const Supp* su )
250 {
251 return su->skind;
252 }
253
VG_(get_supp_string)254 HChar* VG_(get_supp_string) ( const Supp* su )
255 {
256 return su->string;
257 }
258
VG_(get_supp_extra)259 void* VG_(get_supp_extra) ( const Supp* su )
260 {
261 return su->extra;
262 }
263
264
VG_(set_supp_kind)265 void VG_(set_supp_kind) ( Supp* su, SuppKind skind )
266 {
267 su->skind = skind;
268 }
269
VG_(set_supp_string)270 void VG_(set_supp_string) ( Supp* su, HChar* string )
271 {
272 su->string = string;
273 }
274
VG_(set_supp_extra)275 void VG_(set_supp_extra) ( Supp* su, void* extra )
276 {
277 su->extra = extra;
278 }
279
280
281 /*------------------------------------------------------------*/
282 /*--- Helper fns ---*/
283 /*------------------------------------------------------------*/
284
285 // Only show core errors if the tool wants to, we're not running with -q,
286 // and were not outputting XML.
VG_(showing_core_errors)287 Bool VG_(showing_core_errors)(void)
288 {
289 return VG_(needs).core_errors && VG_(clo_verbosity) >= 1 && !VG_(clo_xml);
290 }
291
292 /* Compare errors, to detect duplicates.
293 */
eq_Error(VgRes res,const Error * e1,const Error * e2)294 static Bool eq_Error ( VgRes res, const Error* e1, const Error* e2 )
295 {
296 if (e1->ekind != e2->ekind)
297 return False;
298 if (!VG_(eq_ExeContext)(res, e1->where, e2->where))
299 return False;
300
301 switch (e1->ekind) {
302 //(example code, see comment on CoreSuppKind above)
303 //case ThreadErr:
304 // vg_assert(VG_(needs).core_errors);
305 // return <something>
306 default:
307 if (VG_(needs).tool_errors) {
308 return VG_TDICT_CALL(tool_eq_Error, res, e1, e2);
309 } else {
310 VG_(printf)("\nUnhandled error type: %u. VG_(needs).tool_errors\n"
311 "probably needs to be set.\n",
312 (UInt)e1->ekind);
313 VG_(core_panic)("unhandled error type");
314 }
315 }
316 }
317
318
319 /* Helper functions for suppression generation: print a single line of
320 a suppression pseudo-stack-trace, either in XML or text mode. It's
321 important that the behaviour of these two functions exactly
322 corresponds.
323 */
324 #define ERRTXT_LEN 4096
325
printSuppForIp_XML(UInt n,DiEpoch ep,Addr ip,void * uu_opaque)326 static void printSuppForIp_XML(UInt n, DiEpoch ep, Addr ip, void* uu_opaque)
327 {
328 const HChar *buf;
329 InlIPCursor* iipc = VG_(new_IIPC)(ep, ip);
330 do {
331 if ( VG_(get_fnname_no_cxx_demangle) (ep, ip, &buf, iipc) ) {
332 VG_(printf_xml)(" <sframe> <fun>%pS</fun> </sframe>\n", buf);
333 } else
334 if ( VG_(get_objname)(ep, ip, &buf) ) {
335 VG_(printf_xml)(" <sframe> <obj>%pS</obj> </sframe>\n", buf);
336 } else {
337 VG_(printf_xml)(" <sframe> <obj>*</obj> </sframe>\n");
338 }
339 } while (VG_(next_IIPC)(iipc));
340 VG_(delete_IIPC)(iipc);
341 }
342
printSuppForIp_nonXML(UInt n,DiEpoch ep,Addr ip,void * textV)343 static void printSuppForIp_nonXML(UInt n, DiEpoch ep, Addr ip, void* textV)
344 {
345 const HChar *buf;
346 XArray* /* of HChar */ text = (XArray*)textV;
347 InlIPCursor* iipc = VG_(new_IIPC)(ep, ip);
348 do {
349 if ( VG_(get_fnname_no_cxx_demangle) (ep, ip, &buf, iipc) ) {
350 VG_(xaprintf)(text, " fun:%s\n", buf);
351 } else
352 if ( VG_(get_objname)(ep, ip, &buf) ) {
353 VG_(xaprintf)(text, " obj:%s\n", buf);
354 } else {
355 VG_(xaprintf)(text, " obj:*\n");
356 }
357 } while (VG_(next_IIPC)(iipc));
358 VG_(delete_IIPC)(iipc);
359 }
360
361 /* Generate a suppression for an error, either in text or XML mode.
362 */
gen_suppression(const Error * err)363 static void gen_suppression(const Error* err)
364 {
365 const HChar* name;
366 ExeContext* ec;
367 XArray* /* HChar */ text;
368
369 const HChar* dummy_name = "insert_a_suppression_name_here";
370
371 vg_assert(err);
372
373 ec = VG_(get_error_where)(err);
374 vg_assert(ec);
375
376 name = VG_TDICT_CALL(tool_get_error_name, err);
377 if (NULL == name) {
378 VG_(umsg)("(%s does not allow error to be suppressed)\n",
379 VG_(details).name);
380 return;
381 }
382
383 /* In XML mode, we also need to print the plain text version of the
384 suppresion in a CDATA section. What that really means is, we
385 need to generate the plaintext version both in XML and text
386 mode. So generate it into TEXT. */
387 text = VG_(newXA)( VG_(malloc), "errormgr.gen_suppression.1",
388 VG_(free), sizeof(HChar) );
389
390 /* Ok. Generate the plain text version into TEXT. */
391 VG_(xaprintf)(text, "{\n");
392 VG_(xaprintf)(text, " <%s>\n", dummy_name);
393 VG_(xaprintf)(text, " %s:%s\n", VG_(details).name, name);
394
395 HChar *xtra = NULL;
396 SizeT xtra_size = 0;
397 SizeT num_written;
398
399 do {
400 xtra_size += 256;
401 xtra = VG_(realloc)("errormgr.gen_suppression.2", xtra,xtra_size);
402 num_written = VG_TDICT_CALL(tool_get_extra_suppression_info,
403 err, xtra, xtra_size);
404 } while (num_written == xtra_size); // resize buffer and retry
405
406 // Ensure buffer is properly terminated
407 vg_assert(xtra[num_written] == '\0');
408
409 if (num_written)
410 VG_(xaprintf)(text, " %s\n", xtra);
411
412 // Print stack trace elements
413 UInt n_ips = VG_(get_ExeContext_n_ips)(ec);
414 vg_assert(n_ips > 0);
415 vg_assert(n_ips <= VG_DEEPEST_BACKTRACE);
416 VG_(apply_StackTrace)(printSuppForIp_nonXML,
417 text, VG_(get_ExeContext_epoch)(ec),
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, VG_(get_ExeContext_epoch)(ec),
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 actions on error, that is, immediately after an error is printed.
517 These are:
518 * possibly, call the GDB server
519 * possibly, generate a suppression.
520 */
521 static
do_actions_on_error(const Error * err,Bool allow_db_attach)522 void do_actions_on_error(const Error* err, Bool allow_db_attach)
523 {
524 Bool still_noisy = True;
525
526 /* if user wants to debug from a certain error nr, then wait for gdb/vgdb */
527 if (VG_(clo_vgdb) != Vg_VgdbNo
528 && allow_db_attach
529 && VG_(dyn_vgdb_error) <= n_errs_shown) {
530 VG_(umsg)("(action on error) vgdb me ... \n");
531 VG_(gdbserver)( err->tid );
532 VG_(umsg)("Continuing ...\n");
533 }
534
535 /* Or maybe we want to generate the error's suppression? */
536 if (VG_(clo_gen_suppressions) == 2
537 || (VG_(clo_gen_suppressions) == 1
538 && VG_(is_action_requested)( "Print suppression", &still_noisy ))
539 ) {
540 gen_suppression(err);
541 }
542 if (VG_(clo_gen_suppressions) == 1 && !still_noisy)
543 VG_(clo_gen_suppressions) = 0;
544
545 if (VG_(clo_exit_on_first_error)) {
546 if (VG_(clo_xml))
547 VG_(printf_xml)("</valgrindoutput>\n");
548 VG_(umsg)("\n");
549 VG_(umsg)("Exit program on first error (--exit-on-first-error=yes)\n");
550 VG_(client_exit)( VG_(clo_error_exitcode) );
551 }
552 }
553
554
555 /* Prints an error. Not entirely simple because of the differences
556 between XML and text mode output.
557
558 In XML mode:
559
560 * calls the tool's pre-show method, so the tool can create any
561 preamble ahead of the message, if it wants.
562
563 * prints the opening tag, and the <unique> and <tid> fields
564
565 * prints the tool-specific parts of the message
566
567 * if suppression generation is required, a suppression
568
569 * the closing tag
570
571 In text mode:
572
573 * calls the tool's pre-show method, so the tool can create any
574 preamble ahead of the message, if it wants.
575
576 * prints the tool-specific parts of the message
577
578 In both modes:
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>%u</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 %u %s:\n", err->tid, tst->thread_name );
631 } else {
632 VG_(umsg)("Thread %u:\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 Bool any_error = False;
983
984 if (verbosity == 0 && !VG_(clo_show_error_list))
985 return;
986
987 /* If we're printing XML, just show the suppressions and stop. */
988 if (xml) {
989 if (VG_(clo_show_error_list))
990 (void)show_used_suppressions();
991 return;
992 }
993
994 /* We only get here if not printing XML. */
995 VG_(umsg)("ERROR SUMMARY: "
996 "%u errors from %u contexts (suppressed: %u from %u)\n",
997 n_errs_found, n_err_contexts,
998 n_errs_suppressed, n_supp_contexts );
999
1000 if (!VG_(clo_show_error_list))
1001 return;
1002
1003 // We do the following if VG_(clo_show_error_list)
1004 // or at -v or above, and only in non-XML mode.
1005
1006 /* Print the contexts in order of increasing error count.
1007 Once an error is shown, we add a huge value to its count to filter it
1008 out.
1009 After having shown all errors, we reset count to the original value. */
1010 for (i = 0; i < n_err_contexts; i++) {
1011 n_min = (1 << 30) - 1;
1012 p_min = NULL;
1013 for (p = errors; p != NULL; p = p->next) {
1014 if (p->supp != NULL) continue;
1015 if (p->count < n_min) {
1016 n_min = p->count;
1017 p_min = p;
1018 }
1019 }
1020 // XXX: this isn't right. See bug 203651.
1021 if (p_min == NULL) continue; //VG_(core_panic)("show_all_errors()");
1022
1023 any_error = True;
1024 VG_(umsg)("\n");
1025 VG_(umsg)("%d errors in context %d of %u:\n",
1026 p_min->count, i+1, n_err_contexts);
1027 pp_Error( p_min, False/*allow_db_attach*/, False /* xml */ );
1028
1029 // We're not printing XML -- we'd have exited above if so.
1030 vg_assert(! xml);
1031
1032 if ((i+1 == VG_(clo_dump_error))) {
1033 StackTrace ips = VG_(get_ExeContext_StackTrace)(p_min->where);
1034 VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to debugging*/,
1035 ips[0], /*debugging*/True, 0xFE/*verbosity*/,
1036 /*bbs_done*/0,
1037 /*allow redir?*/True);
1038 }
1039
1040 p_min->count = p_min->count + (1 << 30);
1041 }
1042
1043 /* reset the counts, otherwise a 2nd call does not show anything anymore */
1044 for (p = errors; p != NULL; p = p->next) {
1045 if (p->count >= (1 << 30))
1046 p->count = p->count - (1 << 30);
1047 }
1048
1049
1050 any_supp = show_used_suppressions();
1051
1052 if (any_supp)
1053 VG_(umsg)("\n");
1054 // reprint summary, so users don't have to scroll way up to find
1055 // the first printing
1056 if (any_supp || any_error)
1057 VG_(umsg)("ERROR SUMMARY: "
1058 "%u errors from %u contexts (suppressed: %u from %u)\n",
1059 n_errs_found, n_err_contexts, n_errs_suppressed,
1060 n_supp_contexts );
1061 }
1062
VG_(show_last_error)1063 void VG_(show_last_error) ( void )
1064 {
1065 if (n_err_contexts == 0) {
1066 VG_(umsg)("No errors yet\n");
1067 return;
1068 }
1069
1070 pp_Error( errors, False/*allow_db_attach*/, False/*xml*/ );
1071 }
1072
1073
1074 /* Show occurrence counts of all errors, in XML form. */
VG_(show_error_counts_as_XML)1075 void VG_(show_error_counts_as_XML) ( void )
1076 {
1077 Error* err;
1078 VG_(printf_xml)("<errorcounts>\n");
1079 for (err = errors; err != NULL; err = err->next) {
1080 if (err->supp != NULL)
1081 continue;
1082 if (err->count <= 0)
1083 continue;
1084 VG_(printf_xml)(" <pair>\n");
1085 VG_(printf_xml)(" <count>%d</count>\n", err->count);
1086 VG_(printf_xml)(" <unique>0x%x</unique>\n", err->unique);
1087 VG_(printf_xml)(" </pair>\n");
1088 }
1089 VG_(printf_xml)("</errorcounts>\n");
1090 VG_(printf_xml)("\n");
1091 }
1092
1093
1094 /*------------------------------------------------------------*/
1095 /*--- Suppression parsing ---*/
1096 /*------------------------------------------------------------*/
1097
1098 /* Get the next char from fd into *out_buf. Returns 1 if success,
1099 0 if eof or < 0 if error. */
1100
get_char(Int fd,HChar * out_buf)1101 static Int get_char ( Int fd, HChar* out_buf )
1102 {
1103 Int r;
1104 static HChar buf[256];
1105 static Int buf_size = 0;
1106 static Int buf_used = 0;
1107 vg_assert(buf_size >= 0 && buf_size <= sizeof buf);
1108 vg_assert(buf_used >= 0 && buf_used <= buf_size);
1109 if (buf_used == buf_size) {
1110 r = VG_(read)(fd, buf, sizeof buf);
1111 if (r < 0) return r; /* read failed */
1112 vg_assert(r >= 0 && r <= sizeof buf);
1113 buf_size = r;
1114 buf_used = 0;
1115 }
1116 if (buf_size == 0)
1117 return 0; /* eof */
1118 vg_assert(buf_size >= 0 && buf_size <= sizeof buf);
1119 vg_assert(buf_used >= 0 && buf_used < buf_size);
1120 *out_buf = buf[buf_used];
1121 buf_used++;
1122 return 1;
1123 }
1124
1125 // Get a non blank non comment line.
1126 // Returns True if eof.
get_nbnc_line(Int fd,HChar ** bufpp,SizeT * nBufp,Int * lineno)1127 static Bool get_nbnc_line ( Int fd, HChar** bufpp, SizeT* nBufp, Int* lineno )
1128 {
1129 HChar* buf = *bufpp;
1130 SizeT nBuf = *nBufp;
1131 HChar ch;
1132 Int n, i;
1133
1134 vg_assert(lineno); // lineno needed to correctly track line numbers.
1135
1136 while (True) {
1137 buf[0] = 0;
1138 /* First, read until a non-blank char appears. */
1139 while (True) {
1140 n = get_char(fd, &ch);
1141 if (n == 1 && !VG_(isspace)(ch)) break;
1142 if (n == 1 && ch == '\n')
1143 (*lineno)++;
1144 if (n <= 0) return True;
1145 }
1146
1147 /* Now, read the line into buf. */
1148 i = 0;
1149 buf[i++] = ch; buf[i] = 0;
1150 while (True) {
1151 n = get_char(fd, &ch);
1152 if (n <= 0) return False; /* the next call will return True */
1153 if (ch == '\n')
1154 (*lineno)++;
1155 if (ch == '\n') break;
1156 if (i > 0 && i == nBuf-1) {
1157 *nBufp = nBuf = nBuf * 2;
1158 #define RIDICULOUS 100000
1159 vg_assert2(nBuf < RIDICULOUS, // Just a sanity check, really.
1160 "VG_(get_line): line longer than %d chars, aborting\n",
1161 RIDICULOUS);
1162 *bufpp = buf = VG_(realloc)("errormgr.get_line.1", buf, nBuf);
1163 }
1164 buf[i++] = ch; buf[i] = 0;
1165 }
1166 while (i > 1 && VG_(isspace)(buf[i-1])) {
1167 i--; buf[i] = 0;
1168 };
1169
1170 // VG_(printf)("The line *%p %d is '%s'\n", lineno, *lineno, buf);
1171 /* Ok, we have a line. If a non-comment line, return.
1172 If a comment line, start all over again. */
1173 if (buf[0] != '#') return False;
1174 }
1175 }
1176
1177 // True if buf starts with fun: or obj: or is ...
is_location_line(const HChar * buf)1178 static Bool is_location_line (const HChar* buf)
1179 {
1180 return VG_(strncmp)(buf, "fun:", 4) == 0
1181 || VG_(strncmp)(buf, "obj:", 4) == 0
1182 || VG_(strcmp)(buf, "...") == 0;
1183 }
1184
VG_(get_line)1185 Bool VG_(get_line) ( Int fd, HChar** bufpp, SizeT* nBufp, Int* lineno )
1186 {
1187 Bool eof = get_nbnc_line (fd, bufpp, nBufp, lineno);
1188
1189 if (eof)
1190 return True;
1191
1192 if (is_location_line(*bufpp))
1193 return True; // Not a extra suppr line
1194 else
1195 return False; // A suppression extra line
1196 }
1197
1198 /* True if s contains no wildcard (?, *) characters. */
is_simple_str(const HChar * s)1199 static Bool is_simple_str (const HChar *s)
1200 {
1201 while (*s) {
1202 if (*s == '?' || *s == '*')
1203 return False;
1204 s++;
1205 }
1206 return True;
1207 }
1208
1209 /* buf contains the raw name of a caller, supposedly either
1210 fun:some_function_name or
1211 obj:some_object_name or
1212 src:some_file_name or
1213 src:some_file_name:line# or
1214 ...
1215 Set p->ty and p->name accordingly.
1216 p->name is allocated and set to the string
1217 after the descriptor (fun:, obj:, or src: san line#) part.
1218 p->lineno is set to non-zero if line# specified; 0 otherwise.
1219 Returns False if failed.
1220 */
setLocationTy(SuppLoc * p,const HChar * buf)1221 static Bool setLocationTy ( SuppLoc* p, const HChar *buf )
1222 {
1223 if (VG_(strncmp)(buf, "fun:", 4) == 0) {
1224 p->name = VG_(strdup)("errormgr.sLTy.1", buf+4);
1225 p->name_is_simple_str = is_simple_str (p->name);
1226 p->ty = FunName;
1227 return True;
1228 }
1229 if (VG_(strncmp)(buf, "obj:", 4) == 0) {
1230 p->name = VG_(strdup)("errormgr.sLTy.2", buf+4);
1231 p->name_is_simple_str = is_simple_str (p->name);
1232 p->ty = ObjName;
1233 return True;
1234 }
1235 if (VG_(strncmp)(buf, "src:", 4) == 0) {
1236 p->name = VG_(strdup)("errormgr.sLTy.3", buf+4);
1237 p->name_is_simple_str = is_simple_str (p->name);
1238 p->ty = SrcName;
1239 HChar *s = VG_(strchr)(p->name, ':');
1240 if (s != NULL) {
1241 *s++ = '\0'; // trim colon
1242 p->lineno = (UInt) VG_(strtoll10)(s, NULL);
1243 } else {
1244 p->lineno = 0;
1245 }
1246 return True;
1247 }
1248 if (VG_(strcmp)(buf, "...") == 0) {
1249 p->name = NULL;
1250 p->name_is_simple_str = False;
1251 p->ty = DotDotDot;
1252 return True;
1253 }
1254 VG_(printf)("location should be \"...\", or should start "
1255 "with \"fun:\", \"obj:\", or \"src:\"\n");
1256 return False;
1257 }
1258
1259
1260 /* Look for "tool" in a string like "tool1,tool2,tool3" */
tool_name_present(const HChar * name,const HChar * names)1261 static Bool tool_name_present(const HChar *name, const HChar *names)
1262 {
1263 Bool found;
1264 HChar *s = NULL; /* Shut gcc up */
1265 Int len = VG_(strlen)(name);
1266
1267 found = (NULL != (s = VG_(strstr)(names, name))
1268 && (s == names || *(s-1) == ',')
1269 && (*(s+len) == ',' || *(s+len) == '\0'));
1270
1271 return found;
1272 }
1273
1274 /* Read suppressions from the file specified in
1275 VG_(clo_suppressions)[clo_suppressions_i]
1276 and place them in the suppressions list. If there's any difficulty
1277 doing this, just give up -- there's no point in trying to recover.
1278 */
load_one_suppressions_file(Int clo_suppressions_i)1279 static void load_one_suppressions_file ( Int clo_suppressions_i )
1280 {
1281 const HChar* filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1282 clo_suppressions_i);
1283 SysRes sres;
1284 Int fd, i, j, lineno = 0;
1285 Bool got_a_location_line_read_by_tool;
1286 Bool eof;
1287 SizeT nBuf = 200;
1288 HChar* buf = VG_(malloc)("errormgr.losf.1", nBuf);
1289 HChar* tool_names;
1290 HChar* supp_name;
1291 const HChar* err_str = NULL;
1292 SuppLoc tmp_callers[VG_DEEPEST_BACKTRACE];
1293
1294 // Check it's not a directory.
1295 if (VG_(is_dir)( filename )) {
1296 if (VG_(clo_xml))
1297 VG_(printf_xml)("</valgrindoutput>\n");
1298 VG_(umsg)("FATAL: suppressions file \"%s\" is a directory\n", filename );
1299 VG_(exit)(1);
1300 }
1301
1302 // Open the suppression file.
1303 sres = VG_(open)( filename, VKI_O_RDONLY, 0 );
1304 if (sr_isError(sres)) {
1305 if (VG_(clo_xml))
1306 VG_(printf_xml)("</valgrindoutput>\n");
1307 VG_(umsg)("FATAL: can't open suppressions file \"%s\"\n", filename );
1308 VG_(exit)(1);
1309 }
1310 fd = sr_Res(sres);
1311
1312 # define BOMB(S) { err_str = S; goto syntax_error; }
1313
1314 while (True) {
1315 /* Assign and initialise the two suppression halves (core and tool) */
1316 Supp* supp;
1317 supp = VG_(malloc)("errormgr.losf.1", sizeof(Supp));
1318 supp->count = 0;
1319
1320 // Initialise temporary reading-in buffer.
1321 for (i = 0; i < VG_DEEPEST_BACKTRACE; i++) {
1322 tmp_callers[i].ty = NoName;
1323 tmp_callers[i].name_is_simple_str = False;
1324 tmp_callers[i].name = NULL;
1325 }
1326
1327 supp->string = supp->extra = NULL;
1328
1329 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1330 if (eof) {
1331 VG_(free)(supp);
1332 break;
1333 }
1334
1335 if (!VG_STREQ(buf, "{")) BOMB("expected '{' or end-of-file");
1336
1337 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1338
1339 if (eof || VG_STREQ(buf, "}")) BOMB("unexpected '}'");
1340
1341 supp->sname = VG_(strdup)("errormgr.losf.2", buf);
1342 supp->clo_suppressions_i = clo_suppressions_i;
1343 supp->sname_lineno = lineno;
1344
1345 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1346
1347 if (eof) BOMB("unexpected end-of-file (expecting tool:suppr)");
1348
1349 /* Check it has the "tool1,tool2,...:supp" form (look for ':') */
1350 i = 0;
1351 while (True) {
1352 if (buf[i] == ':') break;
1353 if (buf[i] == '\0') BOMB("malformed 'tool1,tool2,...:supp' line");
1354 i++;
1355 }
1356 buf[i] = '\0'; /* Replace ':', splitting into two strings */
1357
1358 tool_names = & buf[0];
1359 supp_name = & buf[i+1];
1360
1361 if (VG_(needs).core_errors && tool_name_present("core", tool_names)) {
1362 // A core suppression
1363 //(example code, see comment on CoreSuppKind above)
1364 //if (VG_STREQ(supp_name, "Thread"))
1365 // supp->skind = ThreadSupp;
1366 //else
1367 BOMB("unknown core suppression type");
1368 }
1369 else if (VG_(needs).tool_errors
1370 && tool_name_present(VG_(details).name, tool_names)) {
1371 // A tool suppression
1372 if (VG_TDICT_CALL(tool_recognised_suppression, supp_name, supp)) {
1373 /* Do nothing, function fills in supp->skind */
1374 } else {
1375 BOMB("unknown tool suppression type");
1376 }
1377 }
1378 else {
1379 // Ignore rest of suppression
1380 while (True) {
1381 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1382 if (eof) BOMB("unexpected end-of-file (when skipping suppression)");
1383 if (VG_STREQ(buf, "}"))
1384 break;
1385 }
1386 VG_(free)(supp->sname);
1387 VG_(free)(supp);
1388 continue;
1389 }
1390
1391 buf[0] = 0;
1392 // tool_read_extra_suppression_info might read lines
1393 // from fd till a location line.
1394 if (VG_(needs).tool_errors
1395 && !VG_TDICT_CALL(tool_read_extra_suppression_info,
1396 fd, &buf, &nBuf, &lineno, supp)) {
1397 BOMB("bad or missing extra suppression info");
1398 }
1399
1400 got_a_location_line_read_by_tool = buf[0] != 0 && is_location_line(buf);
1401
1402 /* the main frame-descriptor reading loop */
1403 i = 0;
1404 while (True) {
1405 if (got_a_location_line_read_by_tool) {
1406 got_a_location_line_read_by_tool = False;
1407 eof = False;
1408 } else {
1409 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1410 }
1411 if (eof)
1412 BOMB("unexpected end-of-file (when reading stack trace)");
1413 if (VG_STREQ(buf, "}")) {
1414 if (i > 0) {
1415 break;
1416 } else {
1417 BOMB("missing stack trace");
1418 }
1419 }
1420 if (i == VG_DEEPEST_BACKTRACE)
1421 BOMB("too many callers in stack trace");
1422 if (i > 0 && i >= VG_(clo_backtrace_size))
1423 break;
1424 if (!setLocationTy(&(tmp_callers[i]), buf))
1425 BOMB("location should be \"...\", or should start "
1426 "with \"fun:\", \"obj:\", or \"src:\"");
1427 i++;
1428 }
1429
1430 // If the num callers is >= VG_(clo_backtrace_size), ignore any extra
1431 // lines and grab the '}'.
1432 if (!VG_STREQ(buf, "}")) {
1433 do {
1434 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1435 } while (!eof && !VG_STREQ(buf, "}"));
1436 }
1437
1438 // Reject entries which are entirely composed of frame
1439 // level wildcards.
1440 vg_assert(i > 0); // guaranteed by frame-descriptor reading loop
1441 for (j = 0; j < i; j++) {
1442 if (tmp_callers[j].ty == FunName || tmp_callers[j].ty == ObjName
1443 || tmp_callers[j].ty == SrcName) {
1444 break;
1445 }
1446 vg_assert(tmp_callers[j].ty == DotDotDot);
1447 }
1448 vg_assert(j >= 0 && j <= i);
1449 if (j == i) {
1450 // we didn't find any non-"..." entries
1451 BOMB("suppression must contain at least one location "
1452 "line which is not \"...\"");
1453 }
1454
1455 // Copy tmp_callers[] into supp->callers[]
1456 supp->n_callers = i;
1457 supp->callers = VG_(malloc)("errormgr.losf.4", i * sizeof(SuppLoc));
1458 for (i = 0; i < supp->n_callers; i++) {
1459 supp->callers[i] = tmp_callers[i];
1460 }
1461
1462 supp->next = suppressions;
1463 suppressions = supp;
1464 }
1465 VG_(free)(buf);
1466 VG_(close)(fd);
1467 return;
1468
1469 syntax_error:
1470 if (VG_(clo_xml))
1471 VG_(printf_xml)("</valgrindoutput>\n");
1472 VG_(umsg)("FATAL: in suppressions file \"%s\" near line %d:\n",
1473 filename, lineno );
1474 VG_(umsg)(" %s\n", err_str );
1475
1476 VG_(close)(fd);
1477 VG_(umsg)("exiting now.\n");
1478 VG_(exit)(1);
1479
1480 # undef BOMB
1481 }
1482
1483
VG_(load_suppressions)1484 void VG_(load_suppressions) ( void )
1485 {
1486 Int i;
1487 suppressions = NULL;
1488 for (i = 0; i < VG_(sizeXA)(VG_(clo_suppressions)); i++) {
1489 if (VG_(clo_verbosity) > 1) {
1490 VG_(dmsg)("Reading suppressions file: %s\n",
1491 *(HChar**) VG_(indexXA)(VG_(clo_suppressions), i));
1492 }
1493 load_one_suppressions_file( i );
1494 }
1495 }
1496
1497
1498 /*------------------------------------------------------------*/
1499 /*--- Matching errors to suppressions ---*/
1500 /*------------------------------------------------------------*/
1501
1502 /* Parameterising functions for the use of VG_(generic_match) in
1503 suppression-vs-error matching. The suppression frames (SuppLoc)
1504 play the role of 'pattern'-element, and the error frames (IPs,
1505 hence simply Addrs) play the role of 'input'. In short then, we're
1506 matching a sequence of Addrs against a pattern composed of a
1507 sequence of SuppLocs.
1508 */
supploc_IsStar(const void * supplocV)1509 static Bool supploc_IsStar ( const void* supplocV )
1510 {
1511 const SuppLoc* supploc = supplocV;
1512 return supploc->ty == DotDotDot;
1513 }
1514
supploc_IsQuery(const void * supplocV)1515 static Bool supploc_IsQuery ( const void* supplocV )
1516 {
1517 return False; /* there's no '?' equivalent in the supp syntax */
1518 }
1519
1520 /* IPtoFunOrObjCompleter is a lazy completer of the IPs
1521 needed to match an error with the suppression patterns.
1522 The matching between an IP and a suppression pattern is done either
1523 with the IP function name or with the IP object name.
1524 First time the fun or obj name is needed for an IP member
1525 of a stack trace, it will be computed and stored in names.
1526 Also, if the IP corresponds to one or more inlined function calls,
1527 the inlined function names are expanded.
1528 The IPtoFunOrObjCompleter type is designed to minimise the nr of
1529 allocations and the nr of debuginfo search. */
1530 typedef
1531 struct {
1532 DiEpoch epoch; // used to interpret .ips
1533 StackTrace ips; // stack trace we are lazily completing.
1534 UWord n_ips; // nr of elements in ips.
1535
1536 // VG_(generic_match) calls haveInputInpC to check
1537 // for the presence of an input element identified by ixInput
1538 // (i.e. a number that identifies the ixInput element of the
1539 // input sequence). It calls supp_pattEQinp to match this input
1540 // element with a pattern.
1541 // When inlining info is used to provide inlined function calls
1542 // in stacktraces, one IP in ips can be expanded in several
1543 // function names. So, each time input (or presence of input)
1544 // is requested by VG_(generic_match), we will expand
1545 // more IP of ips till we have expanded enough to reach the
1546 // input element requested (or we cannot expand anymore).
1547
1548 UWord n_ips_expanded;
1549 // n_ips_expanded maintains the nr of elements in ips that we have
1550 // already expanded.
1551 UWord n_expanded;
1552 // n_expanded maintains the nr of elements resulting from the expansion
1553 // of the n_ips_expanded IPs. Without inlined function calls,
1554 // n_expanded == n_ips_expanded. With inlining info,
1555 // n_expanded >= n_ips_expanded.
1556
1557 Int* n_offsets_per_ip;
1558 // n_offsets_per_ip[i] gives the nr of offsets in fun_offsets and
1559 // obj_offsets resulting of the expansion of ips[i].
1560 // The sum of all n_expanded_per_ip must be equal to n_expanded.
1561 // This array allows to retrieve the position in ips corresponding to
1562 // an ixInput.
1563
1564 // size (in elements) of fun_offsets and obj_offsets.
1565 // (fun|obj)_offsets are reallocated if more space is needed
1566 // to expand an IP.
1567 UWord sz_offsets;
1568
1569 Int* fun_offsets;
1570 // fun_offsets[ixInput] is the offset in names where the
1571 // function name for the ixInput element of the input sequence
1572 // can be found. As one IP of ips can be expanded in several
1573 // function calls due to inlined function calls, we can have more
1574 // elements in fun_offsets than in ips.
1575 // An offset -1 means the function name has not yet been computed.
1576 Int* obj_offsets;
1577 // Similarly, obj_offsets[ixInput] gives the offset for the
1578 // object name for ips[ixInput]
1579 // (-1 meaning object name not yet been computed).
1580
1581 // All function names and object names will be concatenated
1582 // in names. names is reallocated on demand.
1583 HChar *names;
1584 Int names_szB; // size of names.
1585 Int names_free; // offset first free HChar in names.
1586 }
1587 IPtoFunOrObjCompleter;
1588
pp_ip2fo(const IPtoFunOrObjCompleter * ip2fo)1589 static void pp_ip2fo (const IPtoFunOrObjCompleter* ip2fo)
1590 {
1591 Int i, j;
1592 Int o;
1593
1594 VG_(printf)("n_ips %lu n_ips_expanded %lu resulting in n_expanded %lu\n",
1595 ip2fo->n_ips, ip2fo->n_ips_expanded, ip2fo->n_expanded);
1596 for (i = 0; i < ip2fo->n_ips_expanded; i++) {
1597 o = 0;
1598 for (j = 0; j < i; j++)
1599 o += ip2fo->n_offsets_per_ip[j];
1600 VG_(printf)("ips %d 0x08%lx offset [%d,%d] ",
1601 i, ip2fo->ips[i],
1602 o, o+ip2fo->n_offsets_per_ip[i]-1);
1603 for (j = 0; j < ip2fo->n_offsets_per_ip[i]; j++) {
1604 VG_(printf)("%sfun:%s obj:%s\n",
1605 j == 0 ? "" : " ",
1606 ip2fo->fun_offsets[o+j] == -1 ?
1607 "<not expanded>" : &ip2fo->names[ip2fo->fun_offsets[o+j]],
1608 ip2fo->obj_offsets[o+j] == -1 ?
1609 "<not expanded>" : &ip2fo->names[ip2fo->obj_offsets[o+j]]);
1610 }
1611 }
1612 }
1613
1614 /* free the memory in ip2fo.
1615 At debuglog 4, su (or NULL) will be used to show the matching
1616 (or non matching) with ip2fo. */
clearIPtoFunOrObjCompleter(const Supp * su,IPtoFunOrObjCompleter * ip2fo)1617 static void clearIPtoFunOrObjCompleter ( const Supp *su,
1618 IPtoFunOrObjCompleter* ip2fo)
1619 {
1620 if (DEBUG_ERRORMGR || VG_(debugLog_getLevel)() >= 4) {
1621 if (su) {
1622 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1623 su->clo_suppressions_i);
1624 VG_(dmsg)("errormgr matching end suppression %s %s:%d matched:\n",
1625 su->sname,
1626 filename,
1627 su->sname_lineno);
1628 } else {
1629 VG_(dmsg)("errormgr matching end no suppression matched:\n");
1630 }
1631 VG_(pp_StackTrace) (ip2fo->epoch, ip2fo->ips, ip2fo->n_ips);
1632 pp_ip2fo(ip2fo);
1633 }
1634 if (ip2fo->n_offsets_per_ip) VG_(free)(ip2fo->n_offsets_per_ip);
1635 if (ip2fo->fun_offsets) VG_(free)(ip2fo->fun_offsets);
1636 if (ip2fo->obj_offsets) VG_(free)(ip2fo->obj_offsets);
1637 if (ip2fo->names) VG_(free)(ip2fo->names);
1638 }
1639
1640 /* Grow ip2fo->names to ensure we have NEEDED characters available
1641 in ip2fo->names and returns a pointer to the first free char. */
grow_names(IPtoFunOrObjCompleter * ip2fo,SizeT needed)1642 static HChar* grow_names(IPtoFunOrObjCompleter* ip2fo, SizeT needed)
1643 {
1644 if (ip2fo->names_szB
1645 < ip2fo->names_free + needed) {
1646 if (needed < ERRTXT_LEN) needed = ERRTXT_LEN;
1647
1648 ip2fo->names
1649 = VG_(realloc)("foc_names",
1650 ip2fo->names,
1651 ip2fo->names_szB + needed);
1652 ip2fo->names_szB += needed;
1653 }
1654 return ip2fo->names + ip2fo->names_free;
1655 }
1656
1657 /* foComplete returns the function name or object name for ixInput.
1658 If needFun, returns the function name for this input
1659 else returns the object name for this input.
1660 The function name or object name will be computed and added in
1661 names if not yet done. */
foComplete(IPtoFunOrObjCompleter * ip2fo,Int ixInput,Bool needFun)1662 static HChar* foComplete(IPtoFunOrObjCompleter* ip2fo,
1663 Int ixInput, Bool needFun)
1664 {
1665 vg_assert (ixInput < ip2fo->n_expanded);
1666 vg_assert (VG_(clo_read_inline_info) || ixInput < ip2fo->n_ips);
1667
1668 // ptr to the offset array for function offsets (if needFun)
1669 // or object offsets (if !needFun).
1670 Int** offsets;
1671 if (needFun)
1672 offsets = &ip2fo->fun_offsets;
1673 else
1674 offsets = &ip2fo->obj_offsets;
1675
1676 // Complete Fun name or Obj name for IP if not yet done.
1677 if ((*offsets)[ixInput] == -1) {
1678 const HChar* caller;
1679
1680 (*offsets)[ixInput] = ip2fo->names_free;
1681 if (DEBUG_ERRORMGR) VG_(printf)("marking %s ixInput %d offset %d\n",
1682 needFun ? "fun" : "obj",
1683 ixInput, ip2fo->names_free);
1684 if (needFun) {
1685 // With inline info, fn names must have been completed already.
1686 vg_assert (!VG_(clo_read_inline_info));
1687 /* Get the function name into 'caller_name', or "???"
1688 if unknown. */
1689 // Nb: C++-mangled names are used in suppressions. Do, though,
1690 // Z-demangle them, since otherwise it's possible to wind
1691 // up comparing "malloc" in the suppression against
1692 // "_vgrZU_libcZdsoZa_malloc" in the backtrace, and the
1693 // two of them need to be made to match.
1694 if (!VG_(get_fnname_no_cxx_demangle)(ip2fo->epoch,
1695 ip2fo->ips[ixInput],
1696 &caller,
1697 NULL))
1698 caller = "???";
1699 } else {
1700 /* Get the object name into 'caller_name', or "???"
1701 if unknown. */
1702 UWord i;
1703 UWord last_expand_pos_ips = 0;
1704 UWord pos_ips;
1705
1706 /* First get the pos in ips corresponding to ixInput */
1707 for (pos_ips = 0; pos_ips < ip2fo->n_expanded; pos_ips++) {
1708 last_expand_pos_ips += ip2fo->n_offsets_per_ip[pos_ips];
1709 if (ixInput < last_expand_pos_ips)
1710 break;
1711 }
1712 /* pos_ips is the position in ips corresponding to ixInput.
1713 last_expand_pos_ips is the last offset in fun/obj where
1714 ips[pos_ips] has been expanded. */
1715
1716 if (!VG_(get_objname)(ip2fo->epoch, ip2fo->ips[pos_ips], &caller))
1717 caller = "???";
1718
1719 // Have all inlined calls pointing at this object name
1720 for (i = last_expand_pos_ips - ip2fo->n_offsets_per_ip[pos_ips] + 1;
1721 i < last_expand_pos_ips;
1722 i++) {
1723 ip2fo->obj_offsets[i] = ip2fo->names_free;
1724 if (DEBUG_ERRORMGR)
1725 VG_(printf) (" set obj_offset %lu to %d\n",
1726 i, ip2fo->names_free);
1727 }
1728 }
1729 SizeT caller_len = VG_(strlen)(caller);
1730 HChar* caller_name = grow_names(ip2fo, caller_len + 1);
1731 VG_(strcpy)(caller_name, caller);
1732 ip2fo->names_free += caller_len + 1;
1733 if (DEBUG_ERRORMGR) pp_ip2fo(ip2fo);
1734 }
1735
1736 return ip2fo->names + (*offsets)[ixInput];
1737 }
1738
1739 // Grow fun and obj _offsets arrays to have at least n_req elements.
1740 // Ensure n_offsets_per_ip is allocated.
grow_offsets(IPtoFunOrObjCompleter * ip2fo,Int n_req)1741 static void grow_offsets(IPtoFunOrObjCompleter* ip2fo, Int n_req)
1742 {
1743 Int i;
1744
1745 // n_offsets_per_ip must always have the size of the ips array
1746 if (ip2fo->n_offsets_per_ip == NULL) {
1747 ip2fo->n_offsets_per_ip = VG_(malloc)("grow_offsets",
1748 ip2fo->n_ips * sizeof(Int));
1749 for (i = 0; i < ip2fo->n_ips; i++)
1750 ip2fo->n_offsets_per_ip[i] = 0;
1751 }
1752
1753 if (ip2fo->sz_offsets >= n_req)
1754 return;
1755
1756 // Avoid too much re-allocation by allocating at least ip2fo->n_ips
1757 // elements and at least a few more elements than the current size.
1758 if (n_req < ip2fo->n_ips)
1759 n_req = ip2fo->n_ips;
1760 if (n_req < ip2fo->sz_offsets + 5)
1761 n_req = ip2fo->sz_offsets + 5;
1762
1763 ip2fo->fun_offsets = VG_(realloc)("grow_offsets", ip2fo->fun_offsets,
1764 n_req * sizeof(Int));
1765 for (i = ip2fo->sz_offsets; i < n_req; i++)
1766 ip2fo->fun_offsets[i] = -1;
1767
1768 ip2fo->obj_offsets = VG_(realloc)("grow_offsets", ip2fo->obj_offsets,
1769 n_req * sizeof(Int));
1770 for (i = ip2fo->sz_offsets; i < n_req; i++)
1771 ip2fo->obj_offsets[i] = -1;
1772
1773 ip2fo->sz_offsets = n_req;
1774 }
1775
1776 // Expands more IPs from ip2fo->ips.
expandInput(IPtoFunOrObjCompleter * ip2fo,UWord ixInput)1777 static void expandInput (IPtoFunOrObjCompleter* ip2fo, UWord ixInput )
1778 {
1779 while (ip2fo->n_ips_expanded < ip2fo->n_ips
1780 && ip2fo->n_expanded <= ixInput) {
1781 if (VG_(clo_read_inline_info)) {
1782 // Expand one more IP in one or more calls.
1783 const Addr IP = ip2fo->ips[ip2fo->n_ips_expanded];
1784 InlIPCursor *iipc;
1785
1786 iipc = VG_(new_IIPC)(ip2fo->epoch, IP);
1787 // The only thing we really need is the nr of inlined fn calls
1788 // corresponding to the IP we will expand.
1789 // However, computing this is mostly the same as finding
1790 // the function name. So, let's directly complete the function name.
1791 do {
1792 const HChar *caller;
1793 grow_offsets(ip2fo, ip2fo->n_expanded+1);
1794 ip2fo->fun_offsets[ip2fo->n_expanded] = ip2fo->names_free;
1795 if (!VG_(get_fnname_no_cxx_demangle)(ip2fo->epoch, IP,
1796 &caller,
1797 iipc))
1798 caller = "???";
1799 SizeT caller_len = VG_(strlen)(caller);
1800 HChar* caller_name = grow_names(ip2fo, caller_len + 1);
1801 VG_(strcpy)(caller_name, caller);
1802 ip2fo->names_free += caller_len + 1;
1803 ip2fo->n_expanded++;
1804 ip2fo->n_offsets_per_ip[ip2fo->n_ips_expanded]++;
1805 } while (VG_(next_IIPC)(iipc));
1806 ip2fo->n_ips_expanded++;
1807 VG_(delete_IIPC) (iipc);
1808 } else {
1809 // Without inlined fn call info, expansion simply
1810 // consists in allocating enough elements in (fun|obj)_offsets.
1811 // The function or object names themselves will be completed
1812 // when requested.
1813 Int i;
1814 grow_offsets(ip2fo, ip2fo->n_ips);
1815 ip2fo->n_ips_expanded = ip2fo->n_ips;
1816 ip2fo->n_expanded = ip2fo->n_ips;
1817 for (i = 0; i < ip2fo->n_ips; i++)
1818 ip2fo->n_offsets_per_ip[i] = 1;
1819 }
1820 }
1821 }
1822
haveInputInpC(void * inputCompleterV,UWord ixInput)1823 static Bool haveInputInpC (void* inputCompleterV, UWord ixInput )
1824 {
1825 IPtoFunOrObjCompleter* ip2fo = (IPtoFunOrObjCompleter*)inputCompleterV;
1826 expandInput(ip2fo, ixInput);
1827 return ixInput < ip2fo->n_expanded;
1828 }
1829
supp_pattEQinp(const void * supplocV,const void * addrV,void * inputCompleterV,UWord ixInput)1830 static Bool supp_pattEQinp ( const void* supplocV, const void* addrV,
1831 void* inputCompleterV, UWord ixInput )
1832 {
1833 const SuppLoc* supploc = (const SuppLoc*)supplocV; /* PATTERN */
1834 IPtoFunOrObjCompleter* ip2fo = (IPtoFunOrObjCompleter*)inputCompleterV;
1835 const HChar* funobjsrc_name; // Fun, Obj, or src file name.
1836 UInt src_lineno = 0;
1837 Bool ret;
1838
1839 expandInput(ip2fo, ixInput);
1840 vg_assert(ixInput < ip2fo->n_expanded);
1841
1842 /* So, does this IP address match this suppression-line? */
1843 switch (supploc->ty) {
1844 case DotDotDot:
1845 /* supp_pattEQinp is a callback from VG_(generic_match). As
1846 per the spec thereof (see include/pub_tool_seqmatch.h), we
1847 should never get called with a pattern value for which the
1848 _IsStar or _IsQuery function would return True. Hence
1849 this can't happen. */
1850 vg_assert(0);
1851 case ObjName:
1852 funobjsrc_name = foComplete(ip2fo, ixInput, False /*needFun*/);
1853 break;
1854 case FunName:
1855 funobjsrc_name = foComplete(ip2fo, ixInput, True /*needFun*/);
1856 break;
1857 case SrcName: {
1858 const HChar* src_dirname; // placeholder only
1859 ret = VG_(get_filename_linenum)(VG_(current_DiEpoch)(),
1860 ip2fo->ips[ixInput], &funobjsrc_name, &src_dirname, &src_lineno);
1861 if (!ret) {
1862 /* No file name found for location so no way this is a match. */
1863 return ret;
1864 }
1865 break;
1866 }
1867 default:
1868 vg_assert(0);
1869 }
1870
1871 /* So now we have the function or object name in funobjsrc_name, and
1872 the pattern (at the character level) to match against is in
1873 supploc->name. Hence (and leading to a re-entrant call of
1874 VG_(generic_match) if there is a wildcard character): */
1875 if (supploc->name_is_simple_str)
1876 ret = VG_(strcmp) (supploc->name, funobjsrc_name) == 0;
1877 else
1878 ret = VG_(string_match)(supploc->name, funobjsrc_name);
1879 if (ret && supploc->ty == SrcName && supploc->lineno != 0) {
1880 ret = (supploc->lineno == src_lineno);
1881 }
1882 if (DEBUG_ERRORMGR)
1883 VG_(printf) ("supp_pattEQinp %s patt %s ixInput %lu value:%s (lineno:%u vs %u) match:%s\n",
1884 supploc->ty == FunName ? "fun" : (supploc->ty == SrcName ? "src" : "obj"),
1885 supploc->name, ixInput, funobjsrc_name,
1886 supploc->ty == SrcName ? supploc->lineno : 0,
1887 supploc->ty == SrcName ? src_lineno : 0,
1888 ret ? "yes" : "no");
1889 return ret;
1890 }
1891
1892 /////////////////////////////////////////////////////
1893
supp_matches_callers(IPtoFunOrObjCompleter * ip2fo,const Supp * su)1894 static Bool supp_matches_callers(IPtoFunOrObjCompleter* ip2fo,
1895 const Supp* su)
1896 {
1897 /* Unwrap the args and set up the correct parameterisation of
1898 VG_(generic_match), using supploc_IsStar, supploc_IsQuery and
1899 supp_pattEQinp. */
1900 /* note, StackTrace ip2fo->ips === Addr* */
1901 SuppLoc* supps = su->callers;
1902 UWord n_supps = su->n_callers;
1903 UWord szbPatt = sizeof(SuppLoc);
1904 Bool matchAll = False; /* we just want to match a prefix */
1905 if (DEBUG_ERRORMGR) {
1906 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1907 su->clo_suppressions_i);
1908 VG_(dmsg)(" errormgr Checking match with %s %s:%d\n",
1909 su->sname,
1910 filename,
1911 su->sname_lineno);
1912 }
1913 return
1914 VG_(generic_match)(
1915 matchAll,
1916 /*PATT*/supps, szbPatt, n_supps, 0/*initial ixPatt*/,
1917 /*INPUT*/
1918 NULL, 0, 0, /* input/szbInput/nInput 0, as using an inputCompleter */
1919 0/*initial ixInput*/,
1920 supploc_IsStar, supploc_IsQuery, supp_pattEQinp,
1921 ip2fo, haveInputInpC
1922 );
1923 }
1924
1925 /////////////////////////////////////////////////////
1926
1927 static
supp_matches_error(const Supp * su,const Error * err)1928 Bool supp_matches_error(const Supp* su, const Error* err)
1929 {
1930 switch (su->skind) {
1931 //(example code, see comment on CoreSuppKind above)
1932 //case ThreadSupp:
1933 // return (err->ekind == ThreadErr);
1934 default:
1935 if (VG_(needs).tool_errors) {
1936 return VG_TDICT_CALL(tool_error_matches_suppression, err, su);
1937 } else {
1938 VG_(printf)(
1939 "\nUnhandled suppression type: %u. VG_(needs).tool_errors\n"
1940 "probably needs to be set.\n",
1941 (UInt)err->ekind);
1942 VG_(core_panic)("unhandled suppression type");
1943 }
1944 }
1945 }
1946
1947 /////////////////////////////////////////////////////
1948
1949 /* Does an error context match a suppression? ie is this a suppressible
1950 error? If so, return a pointer to the Supp record, otherwise NULL.
1951 Tries to minimise the number of symbol searches since they are expensive.
1952 */
is_suppressible_error(const Error * err)1953 static Supp* is_suppressible_error ( const Error* err )
1954 {
1955 Supp* su;
1956 Supp* su_prev;
1957
1958 IPtoFunOrObjCompleter ip2fo;
1959 /* Conceptually, ip2fo contains an array of function names and an array of
1960 object names, corresponding to the array of IP of err->where.
1961 These names are just computed 'on demand' (so once maximum),
1962 then stored (efficiently, avoiding too many allocs) in ip2fo to be
1963 re-usable for the matching of the same IP with the next suppression
1964 pattern.
1965
1966 VG_(generic_match) gets this 'IP to Fun or Obj name completer' as one
1967 of its arguments. It will then pass it to the function
1968 supp_pattEQinp which will then lazily complete the IP function name or
1969 object name inside ip2fo. Next time the fun or obj name for the same
1970 IP is needed (i.e. for the matching with the next suppr pattern), then
1971 the fun or obj name will not be searched again in the debug info. */
1972
1973 /* stats gathering */
1974 em_supplist_searches++;
1975
1976 /* Prepare the lazy input completer. */
1977 ip2fo.epoch = VG_(get_ExeContext_epoch)(err->where);
1978 ip2fo.ips = VG_(get_ExeContext_StackTrace)(err->where);
1979 ip2fo.n_ips = VG_(get_ExeContext_n_ips)(err->where);
1980 ip2fo.n_ips_expanded = 0;
1981 ip2fo.n_expanded = 0;
1982 ip2fo.sz_offsets = 0;
1983 ip2fo.n_offsets_per_ip = NULL;
1984 ip2fo.fun_offsets = NULL;
1985 ip2fo.obj_offsets = NULL;
1986 ip2fo.names = NULL;
1987 ip2fo.names_szB = 0;
1988 ip2fo.names_free = 0;
1989
1990 /* See if the error context matches any suppression. */
1991 if (DEBUG_ERRORMGR || VG_(debugLog_getLevel)() >= 4)
1992 VG_(dmsg)("errormgr matching begin\n");
1993 su_prev = NULL;
1994 for (su = suppressions; su != NULL; su = su->next) {
1995 em_supplist_cmps++;
1996 if (supp_matches_error(su, err)
1997 && supp_matches_callers(&ip2fo, su)) {
1998 /* got a match. */
1999 /* Inform the tool that err is suppressed by su. */
2000 (void)VG_TDICT_CALL(tool_update_extra_suppression_use, err, su);
2001 /* Move this entry to the head of the list
2002 in the hope of making future searches cheaper. */
2003 if (su_prev) {
2004 vg_assert(su_prev->next == su);
2005 su_prev->next = su->next;
2006 su->next = suppressions;
2007 suppressions = su;
2008 }
2009 clearIPtoFunOrObjCompleter(su, &ip2fo);
2010 return su;
2011 }
2012 su_prev = su;
2013 }
2014 clearIPtoFunOrObjCompleter(NULL, &ip2fo);
2015 return NULL; /* no matches */
2016 }
2017
2018 /* Show accumulated error-list and suppression-list search stats.
2019 */
VG_(print_errormgr_stats)2020 void VG_(print_errormgr_stats) ( void )
2021 {
2022 VG_(dmsg)(
2023 " errormgr: %'lu supplist searches, %'lu comparisons during search\n",
2024 em_supplist_searches, em_supplist_cmps
2025 );
2026 VG_(dmsg)(
2027 " errormgr: %'lu errlist searches, %'lu comparisons during search\n",
2028 em_errlist_searches, em_errlist_cmps
2029 );
2030 }
2031
2032 /*--------------------------------------------------------------------*/
2033 /*--- end ---*/
2034 /*--------------------------------------------------------------------*/
2035