blob: cabc8ae260bcae91dd383105ec6f287d7fadd570 [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
2/*--------------------------------------------------------------------*/
3/*--- Management of error messages. vg_errcontext.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
njnc9539842002-10-02 13:26:35 +00007 This file is part of Valgrind, an extensible x86 protected-mode
8 emulator for monitoring program execution on x86-Unixes.
sewardjde4a1d02002-03-22 01:27:54 +00009
njn0e1b5142003-04-15 14:58:06 +000010 Copyright (C) 2000-2003 Julian Seward
sewardjde4a1d02002-03-22 01:27:54 +000011 jseward@acm.org
sewardjde4a1d02002-03-22 01:27:54 +000012
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
njn25e49d8e72002-09-23 09:36:25 +000028 The GNU General Public License is contained in the file COPYING.
sewardjde4a1d02002-03-22 01:27:54 +000029*/
30
31#include "vg_include.h"
sewardjde4a1d02002-03-22 01:27:54 +000032
33/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +000034/*--- Globals ---*/
sewardjde4a1d02002-03-22 01:27:54 +000035/*------------------------------------------------------------*/
36
sewardjde4a1d02002-03-22 01:27:54 +000037/* The list of error contexts found, both suppressed and unsuppressed.
38 Initially empty, and grows as errors are detected. */
njn810086f2002-11-14 12:42:47 +000039static Error* vg_errors = NULL;
sewardjde4a1d02002-03-22 01:27:54 +000040
41/* The list of suppression directives, as read from the specified
42 suppressions file. */
njn810086f2002-11-14 12:42:47 +000043static Supp* vg_suppressions = NULL;
sewardjde4a1d02002-03-22 01:27:54 +000044
45/* Running count of unsuppressed errors detected. */
njn47363ab2003-04-21 13:24:40 +000046UInt VG_(n_errs_found) = 0;
sewardjde4a1d02002-03-22 01:27:54 +000047
48/* Running count of suppressed errors detected. */
49static UInt vg_n_errs_suppressed = 0;
50
51/* forwards ... */
njn810086f2002-11-14 12:42:47 +000052static Supp* is_suppressible_error ( Error* err );
sewardjde4a1d02002-03-22 01:27:54 +000053
54
55/*------------------------------------------------------------*/
56/*--- Helper fns ---*/
57/*------------------------------------------------------------*/
58
sewardjde4a1d02002-03-22 01:27:54 +000059/* Compare error contexts, to detect duplicates. Note that if they
60 are otherwise the same, the faulting addrs and associated rwoffsets
61 are allowed to be different. */
njn810086f2002-11-14 12:42:47 +000062static Bool eq_Error ( VgRes res, Error* e1, Error* e2 )
sewardjde4a1d02002-03-22 01:27:54 +000063{
njn810086f2002-11-14 12:42:47 +000064 if (e1->ekind != e2->ekind)
sewardjde4a1d02002-03-22 01:27:54 +000065 return False;
njn25e49d8e72002-09-23 09:36:25 +000066 if (!VG_(eq_ExeContext)(res, e1->where, e2->where))
sewardjde4a1d02002-03-22 01:27:54 +000067 return False;
68
njn810086f2002-11-14 12:42:47 +000069 switch (e1->ekind) {
sewardj4dced352002-06-04 22:54:20 +000070 case PThreadErr:
njn25e49d8e72002-09-23 09:36:25 +000071 vg_assert(VG_(needs).core_errors);
njn810086f2002-11-14 12:42:47 +000072 if (e1->string == e2->string)
sewardj4dced352002-06-04 22:54:20 +000073 return True;
njn810086f2002-11-14 12:42:47 +000074 if (0 == VG_(strcmp)(e1->string, e2->string))
sewardj4dced352002-06-04 22:54:20 +000075 return True;
76 return False;
sewardjde4a1d02002-03-22 01:27:54 +000077 default:
njn25e49d8e72002-09-23 09:36:25 +000078 if (VG_(needs).skin_errors)
njn810086f2002-11-14 12:42:47 +000079 return SK_(eq_SkinError)(res, e1, e2);
njn25e49d8e72002-09-23 09:36:25 +000080 else {
81 VG_(printf)("\nUnhandled error type: %u. VG_(needs).skin_errors\n"
82 "probably needs to be set.\n",
njn810086f2002-11-14 12:42:47 +000083 e1->ekind);
njne427a662002-10-02 11:08:25 +000084 VG_(skin_panic)("unhandled error type");
njn25e49d8e72002-09-23 09:36:25 +000085 }
sewardjde4a1d02002-03-22 01:27:54 +000086 }
87}
88
njn810086f2002-11-14 12:42:47 +000089static void pp_Error ( Error* err, Bool printCount )
sewardjde4a1d02002-03-22 01:27:54 +000090{
sewardjde4a1d02002-03-22 01:27:54 +000091 if (printCount)
njn25e49d8e72002-09-23 09:36:25 +000092 VG_(message)(Vg_UserMsg, "Observed %d times:", err->count );
93 if (err->tid > 1)
94 VG_(message)(Vg_UserMsg, "Thread %d:", err->tid );
95
njn810086f2002-11-14 12:42:47 +000096 switch (err->ekind) {
sewardj4dced352002-06-04 22:54:20 +000097 case PThreadErr:
njn25e49d8e72002-09-23 09:36:25 +000098 vg_assert(VG_(needs).core_errors);
njn810086f2002-11-14 12:42:47 +000099 VG_(message)(Vg_UserMsg, "%s", err->string );
njn25e49d8e72002-09-23 09:36:25 +0000100 VG_(pp_ExeContext)(err->where);
sewardj4dced352002-06-04 22:54:20 +0000101 break;
sewardjde4a1d02002-03-22 01:27:54 +0000102 default:
njn25e49d8e72002-09-23 09:36:25 +0000103 if (VG_(needs).skin_errors)
njn43c799e2003-04-08 00:08:52 +0000104 SK_(pp_SkinError)( err );
njn25e49d8e72002-09-23 09:36:25 +0000105 else {
106 VG_(printf)("\nUnhandled error type: %u. VG_(needs).skin_errors\n"
107 "probably needs to be set?\n",
njn810086f2002-11-14 12:42:47 +0000108 err->ekind);
njne427a662002-10-02 11:08:25 +0000109 VG_(skin_panic)("unhandled error type");
njn25e49d8e72002-09-23 09:36:25 +0000110 }
sewardjde4a1d02002-03-22 01:27:54 +0000111 }
112}
113
sewardjde4a1d02002-03-22 01:27:54 +0000114/* Figure out if we want to attach for GDB for this error, possibly
115 by asking the user. */
njn43c799e2003-04-08 00:08:52 +0000116Bool VG_(is_action_requested) ( Char* action, Bool* clo )
sewardjde4a1d02002-03-22 01:27:54 +0000117{
118 Char ch, ch2;
119 Int res;
120
njn43c799e2003-04-08 00:08:52 +0000121 if (*clo == False)
sewardjde4a1d02002-03-22 01:27:54 +0000122 return False;
123
124 VG_(message)(Vg_UserMsg, "");
125
126 again:
127 VG_(printf)(
128 "==%d== "
njn43c799e2003-04-08 00:08:52 +0000129 "---- %s ? --- [Return/N/n/Y/y/C/c] ---- ",
130 VG_(getpid)(), action
sewardjde4a1d02002-03-22 01:27:54 +0000131 );
132
sewardj6024b212003-07-13 10:54:33 +0000133 res = VG_(read)(VG_(clo_input_fd), &ch, 1);
sewardjde4a1d02002-03-22 01:27:54 +0000134 if (res != 1) goto ioerror;
135 /* res == 1 */
136 if (ch == '\n') return False;
137 if (ch != 'N' && ch != 'n' && ch != 'Y' && ch != 'y'
138 && ch != 'C' && ch != 'c') goto again;
139
sewardj6024b212003-07-13 10:54:33 +0000140 res = VG_(read)(VG_(clo_input_fd), &ch2, 1);
sewardjde4a1d02002-03-22 01:27:54 +0000141 if (res != 1) goto ioerror;
142 if (ch2 != '\n') goto again;
143
njn43c799e2003-04-08 00:08:52 +0000144 /* No, don't want to do action. */
sewardjde4a1d02002-03-22 01:27:54 +0000145 if (ch == 'n' || ch == 'N') return False;
njn43c799e2003-04-08 00:08:52 +0000146 /* Yes, want to do action. */
sewardjde4a1d02002-03-22 01:27:54 +0000147 if (ch == 'y' || ch == 'Y') return True;
njn43c799e2003-04-08 00:08:52 +0000148 /* No, don't want to do action, and don't ask again either. */
sewardjde4a1d02002-03-22 01:27:54 +0000149 vg_assert(ch == 'c' || ch == 'C');
150
151 ioerror:
njn43c799e2003-04-08 00:08:52 +0000152 *clo = False;
sewardjde4a1d02002-03-22 01:27:54 +0000153 return False;
154}
155
156
njn25e49d8e72002-09-23 09:36:25 +0000157/* I've gone all object-oriented... initialisation depends on where the
158 error comes from:
159
160 - If from generated code (tst == NULL), the %EIP/%EBP values that we
njn3e884182003-04-15 13:03:23 +0000161 need in order to attach GDB are picked up out of VG_(baseBlock) rather
162 than from the thread table (vg_threads in vg_scheduler.c).
njn25e49d8e72002-09-23 09:36:25 +0000163
164 - If not from generated code but in response to requests passed back to
165 the scheduler (tst != NULL), we pick up %EIP/%EBP values from the
166 stored thread state, not from VG_(baseBlock).
167*/
168static __inline__
njn43c799e2003-04-08 00:08:52 +0000169void construct_error ( Error* err, ThreadState* tst, ErrorKind ekind, Addr a,
njn3e884182003-04-15 13:03:23 +0000170 Char* s, void* extra, ExeContext* where,
171 /*out*/Addr* m_eip, /*out*/Addr* m_esp,
172 /*out*/Addr* m_ebp )
sewardjde4a1d02002-03-22 01:27:54 +0000173{
njn810086f2002-11-14 12:42:47 +0000174 /* Core-only parts */
njn25e49d8e72002-09-23 09:36:25 +0000175 err->next = NULL;
176 err->supp = NULL;
177 err->count = 1;
njn43c799e2003-04-08 00:08:52 +0000178 if (NULL == where)
179 err->where = VG_(get_ExeContext)( tst );
180 else
181 err->where = where;
njn1d6c4bc2002-11-21 13:38:08 +0000182
njn25e49d8e72002-09-23 09:36:25 +0000183 if (NULL == tst) {
184 err->tid = VG_(get_current_tid)();
njn3e884182003-04-15 13:03:23 +0000185 *m_eip = VG_(baseBlock)[VGOFF_(m_eip)];
186 *m_esp = VG_(baseBlock)[VGOFF_(m_esp)];
187 *m_ebp = VG_(baseBlock)[VGOFF_(m_ebp)];
njn25e49d8e72002-09-23 09:36:25 +0000188 } else {
njn25e49d8e72002-09-23 09:36:25 +0000189 err->tid = tst->tid;
njn3e884182003-04-15 13:03:23 +0000190 *m_eip = tst->m_eip;
191 *m_esp = tst->m_esp;
192 *m_ebp = tst->m_ebp;
njn25e49d8e72002-09-23 09:36:25 +0000193 }
194
njn810086f2002-11-14 12:42:47 +0000195 /* Skin-relevant parts */
196 err->ekind = ekind;
197 err->addr = a;
198 err->string = s;
199 err->extra = extra;
njn25e49d8e72002-09-23 09:36:25 +0000200
201 /* sanity... */
202 vg_assert(err->tid >= 0 && err->tid < VG_N_THREADS);
203}
204
njn43c799e2003-04-08 00:08:52 +0000205void VG_(gen_suppression)(Error* err)
206{
sewardj05bcdcb2003-05-18 10:05:38 +0000207 Int i;
njn43c799e2003-04-08 00:08:52 +0000208 UChar buf[M_VG_ERRTXT];
209 ExeContext* ec = VG_(get_error_where)(err);
210 Int stop_at = VG_(clo_backtrace_size);
njn43c799e2003-04-08 00:08:52 +0000211
njn633de322003-05-12 20:40:13 +0000212 if (stop_at > 4) stop_at = 4; /* At most four names */
njn43c799e2003-04-08 00:08:52 +0000213 vg_assert(stop_at > 0);
214
215 VG_(printf)("{\n");
216 VG_(printf)(" <insert a suppression name here>\n");
njn6a230532003-07-21 10:38:23 +0000217
218 if (PThreadErr == err->ekind) {
219 VG_(printf)(" core:PThread\n");
220
221 } else {
222 Char* name = SK_(get_error_name)(err);
223 if (NULL == name) {
224 VG_(message)(Vg_UserMsg,
225 "(skin does not allow error to be suppressed)");
226 return;
227 }
228 VG_(printf)(" %s:%s\n", VG_(details).name, name);
229 SK_(print_extra_suppression_info)(err);
230 }
njn43c799e2003-04-08 00:08:52 +0000231
232 /* This loop condensed from VG_(mini_stack_dump)() */
233 i = 0;
234 do {
235 Addr eip = ec->eips[i];
236 if (i > 0)
237 eip--; /* point to calling line */
238
239 if ( VG_(get_fnname_nodemangle) (eip, buf, M_VG_ERRTXT) ) {
240 VG_(printf)(" fun:%s\n", buf);
241 } else if ( VG_(get_objname)(eip, buf, M_VG_ERRTXT) ) {
242 VG_(printf)(" obj:%s\n", buf);
243 } else {
244 VG_(printf)(" ???:??? "
245 "# unknown, suppression will not work, sorry)\n");
246 }
247 i++;
248 } while (i < stop_at && ec->eips[i] != 0);
249
250 VG_(printf)("}\n");
251}
252
njnb4aee052003-04-15 14:09:58 +0000253static
njn3e884182003-04-15 13:03:23 +0000254void do_actions_on_error(Error* err, Bool allow_GDB_attach,
255 Addr m_eip, Addr m_esp, Addr m_ebp )
njn43c799e2003-04-08 00:08:52 +0000256{
257 /* Perhaps we want a GDB attach at this point? */
njn3e884182003-04-15 13:03:23 +0000258 if (allow_GDB_attach &&
259 VG_(is_action_requested)( "Attach to GDB", & VG_(clo_GDB_attach) ))
260 {
261 VG_(swizzle_esp_then_start_GDB)( m_eip, m_esp, m_ebp );
njn43c799e2003-04-08 00:08:52 +0000262 }
263 /* Or maybe we want to generate the error's suppression? */
264 if (VG_(is_action_requested)( "Print suppression",
265 & VG_(clo_gen_suppressions) )) {
266 VG_(gen_suppression)(err);
267 }
268}
269
270/* Shared between VG_(maybe_record_error)() and VG_(unique_error)(),
271 just for pretty printing purposes. */
272static Bool is_first_shown_context = True;
273
njn25e49d8e72002-09-23 09:36:25 +0000274/* Top-level entry point to the error management subsystem.
275 All detected errors are notified here; this routine decides if/when the
276 user should see the error. */
277void VG_(maybe_record_error) ( ThreadState* tst,
278 ErrorKind ekind, Addr a, Char* s, void* extra )
279{
njn3e884182003-04-15 13:03:23 +0000280 Addr m_eip, m_esp, m_ebp;
njn810086f2002-11-14 12:42:47 +0000281 Error err;
282 Error* p;
283 Error* p_prev;
njn43c799e2003-04-08 00:08:52 +0000284 UInt extra_size;
njn810086f2002-11-14 12:42:47 +0000285 VgRes exe_res = Vg_MedRes;
njn810086f2002-11-14 12:42:47 +0000286 static Bool stopping_message = False;
287 static Bool slowdown_message = False;
288 static Int vg_n_errs_shown = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000289
sewardjf2537be2002-04-24 21:03:47 +0000290 /* After M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN different errors have
291 been found, or M_VG_COLLECT_NO_ERRORS_AFTER_FOUND total errors
292 have been found, just refuse to collect any more. This stops
293 the burden of the error-management system becoming excessive in
294 extremely buggy programs, although it does make it pretty
295 pointless to continue the Valgrind run after this point. */
sewardj2e432902002-06-13 20:44:00 +0000296 if (VG_(clo_error_limit)
sewardj72f98ff2002-06-13 17:23:38 +0000297 && (vg_n_errs_shown >= M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN
njn47363ab2003-04-21 13:24:40 +0000298 || VG_(n_errs_found) >= M_VG_COLLECT_NO_ERRORS_AFTER_FOUND)) {
sewardjde4a1d02002-03-22 01:27:54 +0000299 if (!stopping_message) {
300 VG_(message)(Vg_UserMsg, "");
sewardjf2537be2002-04-24 21:03:47 +0000301
302 if (vg_n_errs_shown >= M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN) {
303 VG_(message)(Vg_UserMsg,
304 "More than %d different errors detected. "
305 "I'm not reporting any more.",
306 M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN );
307 } else {
308 VG_(message)(Vg_UserMsg,
309 "More than %d total errors detected. "
310 "I'm not reporting any more.",
311 M_VG_COLLECT_NO_ERRORS_AFTER_FOUND );
312 }
313
sewardjde4a1d02002-03-22 01:27:54 +0000314 VG_(message)(Vg_UserMsg,
sewardjf2537be2002-04-24 21:03:47 +0000315 "Final error counts will be inaccurate. Go fix your program!");
sewardj72f98ff2002-06-13 17:23:38 +0000316 VG_(message)(Vg_UserMsg,
sewardj2e432902002-06-13 20:44:00 +0000317 "Rerun with --error-limit=no to disable this cutoff. Note");
sewardj72f98ff2002-06-13 17:23:38 +0000318 VG_(message)(Vg_UserMsg,
njn25e49d8e72002-09-23 09:36:25 +0000319 "that errors may occur in your program without prior warning from");
sewardj72f98ff2002-06-13 17:23:38 +0000320 VG_(message)(Vg_UserMsg,
321 "Valgrind, because errors are no longer being displayed.");
sewardjde4a1d02002-03-22 01:27:54 +0000322 VG_(message)(Vg_UserMsg, "");
323 stopping_message = True;
324 }
325 return;
326 }
327
328 /* After M_VG_COLLECT_ERRORS_SLOWLY_AFTER different errors have
329 been found, be much more conservative about collecting new
330 ones. */
331 if (vg_n_errs_shown >= M_VG_COLLECT_ERRORS_SLOWLY_AFTER) {
njn25e49d8e72002-09-23 09:36:25 +0000332 exe_res = Vg_LowRes;
sewardjde4a1d02002-03-22 01:27:54 +0000333 if (!slowdown_message) {
334 VG_(message)(Vg_UserMsg, "");
335 VG_(message)(Vg_UserMsg,
336 "More than %d errors detected. Subsequent errors",
337 M_VG_COLLECT_ERRORS_SLOWLY_AFTER);
338 VG_(message)(Vg_UserMsg,
339 "will still be recorded, but in less detail than before.");
340 slowdown_message = True;
341 }
342 }
343
njn25e49d8e72002-09-23 09:36:25 +0000344 /* Build ourselves the error */
njn3e884182003-04-15 13:03:23 +0000345 construct_error ( &err, tst, ekind, a, s, extra, NULL,
346 &m_eip, &m_esp, &m_ebp );
sewardjde4a1d02002-03-22 01:27:54 +0000347
348 /* First, see if we've got an error record matching this one. */
njn25e49d8e72002-09-23 09:36:25 +0000349 p = vg_errors;
sewardjde4a1d02002-03-22 01:27:54 +0000350 p_prev = NULL;
351 while (p != NULL) {
njn810086f2002-11-14 12:42:47 +0000352 if (eq_Error(exe_res, p, &err)) {
sewardjde4a1d02002-03-22 01:27:54 +0000353 /* Found it. */
354 p->count++;
355 if (p->supp != NULL) {
356 /* Deal correctly with suppressed errors. */
357 p->supp->count++;
358 vg_n_errs_suppressed++;
359 } else {
njn47363ab2003-04-21 13:24:40 +0000360 VG_(n_errs_found)++;
sewardjde4a1d02002-03-22 01:27:54 +0000361 }
362
363 /* Move p to the front of the list so that future searches
364 for it are faster. */
365 if (p_prev != NULL) {
366 vg_assert(p_prev->next == p);
367 p_prev->next = p->next;
njn25e49d8e72002-09-23 09:36:25 +0000368 p->next = vg_errors;
369 vg_errors = p;
sewardjde4a1d02002-03-22 01:27:54 +0000370 }
371 return;
372 }
373 p_prev = p;
374 p = p->next;
375 }
376
377 /* Didn't see it. Copy and add. */
378
njn43c799e2003-04-08 00:08:52 +0000379 /* OK, we're really going to collect it. The context is on the stack and
380 will disappear shortly, so we must copy it. First do the main
381 (non-`extra') part.
njn25e49d8e72002-09-23 09:36:25 +0000382
njn43c799e2003-04-08 00:08:52 +0000383 Then SK_(update_extra) can update the `extra' part. This is for when
384 there are more details to fill in which take time to work out but
385 don't affect our earlier decision to include the error -- by
njn25e49d8e72002-09-23 09:36:25 +0000386 postponing those details until now, we avoid the extra work in the
njn810086f2002-11-14 12:42:47 +0000387 case where we ignore the error. Ugly.
njn43c799e2003-04-08 00:08:52 +0000388
389 Then, if there is an `extra' part, copy it too, using the size that
390 SK_(update_extra) returned.
391 */
392
393 /* copy main part */
njn810086f2002-11-14 12:42:47 +0000394 p = VG_(arena_malloc)(VG_AR_ERRORS, sizeof(Error));
njn25e49d8e72002-09-23 09:36:25 +0000395 *p = err;
njn43c799e2003-04-08 00:08:52 +0000396
njn6a230532003-07-21 10:38:23 +0000397 /* update `extra', for non-core errors (core ones don't use 'extra') */
398 if (VG_(needs).skin_errors) {
399 extra_size = SK_(update_extra)(p);
njn43c799e2003-04-08 00:08:52 +0000400
njn6a230532003-07-21 10:38:23 +0000401 /* copy `extra' if there is one */
402 if (NULL != p->extra) {
403 void* new_extra = VG_(malloc)(extra_size);
404 VG_(memcpy)(new_extra, p->extra, extra_size);
405 p->extra = new_extra;
406 }
njn43c799e2003-04-08 00:08:52 +0000407 }
408
njn25e49d8e72002-09-23 09:36:25 +0000409 p->next = vg_errors;
410 p->supp = is_suppressible_error(&err);
411 vg_errors = p;
sewardjde4a1d02002-03-22 01:27:54 +0000412 if (p->supp == NULL) {
njn47363ab2003-04-21 13:24:40 +0000413 VG_(n_errs_found)++;
sewardjde4a1d02002-03-22 01:27:54 +0000414 if (!is_first_shown_context)
415 VG_(message)(Vg_UserMsg, "");
njn43c799e2003-04-08 00:08:52 +0000416 pp_Error(p, False);
sewardjde4a1d02002-03-22 01:27:54 +0000417 is_first_shown_context = False;
418 vg_n_errs_shown++;
njn3e884182003-04-15 13:03:23 +0000419 do_actions_on_error(p, /*allow_GDB_attach*/True, m_eip, m_esp, m_ebp );
sewardjde4a1d02002-03-22 01:27:54 +0000420 } else {
421 vg_n_errs_suppressed++;
422 p->supp->count++;
423 }
424}
425
njn43c799e2003-04-08 00:08:52 +0000426/* Second top-level entry point to the error management subsystem, for
427 errors that the skin want to report immediately, eg. because they're
428 guaranteed to only happen once. This avoids all the recording and
429 comparing stuff. But they can be suppressed; returns True if it is
njn47363ab2003-04-21 13:24:40 +0000430 suppressed. Bool `print_error' dictates whether to print the error.
431 Bool `count_error' dictates whether to count the error in VG_(n_errs_found)
432*/
njn43c799e2003-04-08 00:08:52 +0000433Bool VG_(unique_error) ( ThreadState* tst, ErrorKind ekind, Addr a, Char* s,
njn3e884182003-04-15 13:03:23 +0000434 void* extra, ExeContext* where, Bool print_error,
njn47363ab2003-04-21 13:24:40 +0000435 Bool allow_GDB_attach, Bool count_error )
njn43c799e2003-04-08 00:08:52 +0000436{
437 Error err;
njn3e884182003-04-15 13:03:23 +0000438 Addr m_eip, m_esp, m_ebp;
njn43c799e2003-04-08 00:08:52 +0000439
440 /* Build ourselves the error */
njn3e884182003-04-15 13:03:23 +0000441 construct_error ( &err, tst, ekind, a, s, extra, where,
442 &m_eip, &m_esp, &m_ebp );
njn43c799e2003-04-08 00:08:52 +0000443
444 /* Unless it's suppressed, we're going to show it. Don't need to make
445 a copy, because it's only temporary anyway.
446
447 Then update the `extra' part with SK_(update_extra), because that can
448 have an affect on whether it's suppressed. Ignore the size return
449 value of SK_(update_extra), because we're not copying `extra'. */
450 (void)SK_(update_extra)(&err);
451
452 if (NULL == is_suppressible_error(&err)) {
njn47363ab2003-04-21 13:24:40 +0000453 if (count_error)
454 VG_(n_errs_found)++;
njn43c799e2003-04-08 00:08:52 +0000455
456 if (print_error) {
457 if (!is_first_shown_context)
458 VG_(message)(Vg_UserMsg, "");
459 pp_Error(&err, False);
460 is_first_shown_context = False;
461 }
njn3e884182003-04-15 13:03:23 +0000462 do_actions_on_error(&err, allow_GDB_attach, m_eip, m_esp, m_ebp);
njn43c799e2003-04-08 00:08:52 +0000463
464 return False;
465
466 } else {
467 vg_n_errs_suppressed++;
468 return True;
469 }
470}
471
sewardjde4a1d02002-03-22 01:27:54 +0000472
sewardjde4a1d02002-03-22 01:27:54 +0000473/*------------------------------------------------------------*/
474/*--- Exported fns ---*/
475/*------------------------------------------------------------*/
476
njn25e49d8e72002-09-23 09:36:25 +0000477/* These are called not from generated code but from the scheduler */
sewardj8c824512002-04-14 04:16:48 +0000478
njn25e49d8e72002-09-23 09:36:25 +0000479void VG_(record_pthread_error) ( ThreadId tid, Char* msg )
sewardjde4a1d02002-03-22 01:27:54 +0000480{
njn25e49d8e72002-09-23 09:36:25 +0000481 if (! VG_(needs).core_errors) return;
482 VG_(maybe_record_error)( &VG_(threads)[tid], PThreadErr, /*addr*/0, msg,
483 /*extra*/NULL );
sewardjde4a1d02002-03-22 01:27:54 +0000484}
485
sewardj8c824512002-04-14 04:16:48 +0000486/*------------------------------*/
487
sewardjde4a1d02002-03-22 01:27:54 +0000488void VG_(show_all_errors) ( void )
489{
njn810086f2002-11-14 12:42:47 +0000490 Int i, n_min;
491 Int n_err_contexts, n_supp_contexts;
492 Error *p, *p_min;
493 Supp *su;
494 Bool any_supp;
sewardjde4a1d02002-03-22 01:27:54 +0000495
496 if (VG_(clo_verbosity) == 0)
497 return;
498
499 n_err_contexts = 0;
njn25e49d8e72002-09-23 09:36:25 +0000500 for (p = vg_errors; p != NULL; p = p->next) {
sewardjde4a1d02002-03-22 01:27:54 +0000501 if (p->supp == NULL)
502 n_err_contexts++;
503 }
504
505 n_supp_contexts = 0;
506 for (su = vg_suppressions; su != NULL; su = su->next) {
507 if (su->count > 0)
508 n_supp_contexts++;
509 }
sewardjde4a1d02002-03-22 01:27:54 +0000510 VG_(message)(Vg_UserMsg,
511 "ERROR SUMMARY: "
512 "%d errors from %d contexts (suppressed: %d from %d)",
njn47363ab2003-04-21 13:24:40 +0000513 VG_(n_errs_found), n_err_contexts,
sewardjde4a1d02002-03-22 01:27:54 +0000514 vg_n_errs_suppressed, n_supp_contexts );
515
516 if (VG_(clo_verbosity) <= 1)
517 return;
518
519 /* Print the contexts in order of increasing error count. */
520 for (i = 0; i < n_err_contexts; i++) {
521 n_min = (1 << 30) - 1;
522 p_min = NULL;
njn25e49d8e72002-09-23 09:36:25 +0000523 for (p = vg_errors; p != NULL; p = p->next) {
sewardjde4a1d02002-03-22 01:27:54 +0000524 if (p->supp != NULL) continue;
525 if (p->count < n_min) {
526 n_min = p->count;
527 p_min = p;
528 }
529 }
njne427a662002-10-02 11:08:25 +0000530 if (p_min == NULL) VG_(skin_panic)("show_all_errors()");
sewardjde4a1d02002-03-22 01:27:54 +0000531
532 VG_(message)(Vg_UserMsg, "");
533 VG_(message)(Vg_UserMsg, "%d errors in context %d of %d:",
534 p_min->count,
535 i+1, n_err_contexts);
njn810086f2002-11-14 12:42:47 +0000536 pp_Error( p_min, False );
sewardjde4a1d02002-03-22 01:27:54 +0000537
538 if ((i+1 == VG_(clo_dump_error))) {
sewardj1e8cdc92002-04-18 11:37:52 +0000539 VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to below NULLs */,
sewardj22854b92002-11-30 14:00:47 +0000540 p_min->where->eips[0], NULL, NULL, NULL, NULL );
sewardjde4a1d02002-03-22 01:27:54 +0000541 }
542
543 p_min->count = 1 << 30;
544 }
545
546 if (n_supp_contexts > 0)
547 VG_(message)(Vg_DebugMsg, "");
548 any_supp = False;
549 for (su = vg_suppressions; su != NULL; su = su->next) {
550 if (su->count > 0) {
551 any_supp = True;
njn25e49d8e72002-09-23 09:36:25 +0000552 VG_(message)(Vg_DebugMsg, "supp: %4d %s", su->count, su->sname);
sewardjde4a1d02002-03-22 01:27:54 +0000553 }
554 }
555
556 if (n_err_contexts > 0) {
557 if (any_supp)
558 VG_(message)(Vg_UserMsg, "");
559 VG_(message)(Vg_UserMsg,
560 "IN SUMMARY: "
561 "%d errors from %d contexts (suppressed: %d from %d)",
njn47363ab2003-04-21 13:24:40 +0000562 VG_(n_errs_found), n_err_contexts,
sewardjde4a1d02002-03-22 01:27:54 +0000563 vg_n_errs_suppressed,
564 n_supp_contexts );
565 VG_(message)(Vg_UserMsg, "");
566 }
567}
568
569/*------------------------------------------------------------*/
570/*--- Standard suppressions ---*/
571/*------------------------------------------------------------*/
572
573/* Get a non-blank, non-comment line of at most nBuf chars from fd.
574 Skips leading spaces on the line. Return True if EOF was hit instead.
575*/
576
577#define VG_ISSPACE(ch) (((ch)==' ') || ((ch)=='\n') || ((ch)=='\t'))
578
njn4ba5a792002-09-30 10:23:54 +0000579Bool VG_(get_line) ( Int fd, Char* buf, Int nBuf )
sewardjde4a1d02002-03-22 01:27:54 +0000580{
581 Char ch;
582 Int n, i;
583 while (True) {
584 /* First, read until a non-blank char appears. */
585 while (True) {
586 n = VG_(read)(fd, &ch, 1);
587 if (n == 1 && !VG_ISSPACE(ch)) break;
588 if (n == 0) return True;
589 }
590
591 /* Now, read the line into buf. */
592 i = 0;
593 buf[i++] = ch; buf[i] = 0;
594 while (True) {
595 n = VG_(read)(fd, &ch, 1);
596 if (n == 0) return False; /* the next call will return True */
597 if (ch == '\n') break;
598 if (i > 0 && i == nBuf-1) i--;
599 buf[i++] = ch; buf[i] = 0;
600 }
601 while (i > 1 && VG_ISSPACE(buf[i-1])) {
602 i--; buf[i] = 0;
603 };
604
605 /* VG_(printf)("The line is `%s'\n", buf); */
606 /* Ok, we have a line. If a non-comment line, return.
607 If a comment line, start all over again. */
608 if (buf[0] != '#') return False;
609 }
610}
611
612
613/* *p_caller contains the raw name of a caller, supposedly either
614 fun:some_function_name or
615 obj:some_object_name.
616 Set *p_ty accordingly and advance *p_caller over the descriptor
617 (fun: or obj:) part.
618 Returns False if failed.
619*/
njn25e49d8e72002-09-23 09:36:25 +0000620static Bool setLocationTy ( Char** p_caller, SuppLocTy* p_ty )
sewardjde4a1d02002-03-22 01:27:54 +0000621{
622 if (VG_(strncmp)(*p_caller, "fun:", 4) == 0) {
623 (*p_caller) += 4;
624 *p_ty = FunName;
625 return True;
626 }
627 if (VG_(strncmp)(*p_caller, "obj:", 4) == 0) {
628 (*p_caller) += 4;
629 *p_ty = ObjName;
630 return True;
631 }
632 VG_(printf)("location should start with fun: or obj:\n");
633 return False;
634}
635
636
njn11cc9252002-10-07 14:42:59 +0000637/* Look for "skin" in a string like "skin1,skin2,skin3" */
638static __inline__
639Bool skin_name_present(Char *name, Char *names)
640{
641 Bool found;
642 Char *s = NULL; /* Shut gcc up */
643 Int len = VG_(strlen)(name);
644
645 found = (NULL != (s = VG_(strstr)(names, name)) &&
646 (s == names || *(s-1) == ',') &&
647 (*(s+len) == ',' || *(s+len) == '\0')
648 );
649
650 return found;
651}
652
sewardjde4a1d02002-03-22 01:27:54 +0000653/* Read suppressions from the file specified in vg_clo_suppressions
654 and place them in the suppressions list. If there's any difficulty
655 doing this, just give up -- there's no point in trying to recover.
656*/
sewardjde4a1d02002-03-22 01:27:54 +0000657static void load_one_suppressions_file ( Char* filename )
658{
659# define N_BUF 200
njnc40c3a82002-10-02 11:02:27 +0000660 Int fd, i;
661 Bool eof;
662 Char buf[N_BUF+1];
njn11cc9252002-10-07 14:42:59 +0000663 Char* skin_names;
njnc40c3a82002-10-02 11:02:27 +0000664 Char* supp_name;
665
njn25e49d8e72002-09-23 09:36:25 +0000666 fd = VG_(open)( filename, VKI_O_RDONLY, 0 );
sewardjde4a1d02002-03-22 01:27:54 +0000667 if (fd == -1) {
njn25e49d8e72002-09-23 09:36:25 +0000668 VG_(message)(Vg_UserMsg, "FATAL: can't open suppressions file `%s'",
sewardjde4a1d02002-03-22 01:27:54 +0000669 filename );
670 VG_(exit)(1);
671 }
672
673 while (True) {
njn25e49d8e72002-09-23 09:36:25 +0000674 /* Assign and initialise the two suppression halves (core and skin) */
njn810086f2002-11-14 12:42:47 +0000675 Supp* supp;
676 supp = VG_(arena_malloc)(VG_AR_CORE, sizeof(Supp));
sewardjde4a1d02002-03-22 01:27:54 +0000677 supp->count = 0;
njn25e49d8e72002-09-23 09:36:25 +0000678 for (i = 0; i < VG_N_SUPP_CALLERS; i++) supp->caller[i] = NULL;
njn810086f2002-11-14 12:42:47 +0000679 supp->string = supp->extra = NULL;
sewardjde4a1d02002-03-22 01:27:54 +0000680
njn4ba5a792002-09-30 10:23:54 +0000681 eof = VG_(get_line) ( fd, buf, N_BUF );
sewardjde4a1d02002-03-22 01:27:54 +0000682 if (eof) break;
683
njn43c799e2003-04-08 00:08:52 +0000684 if (!VG_STREQ(buf, "{")) goto syntax_error;
sewardjde4a1d02002-03-22 01:27:54 +0000685
njn4ba5a792002-09-30 10:23:54 +0000686 eof = VG_(get_line) ( fd, buf, N_BUF );
njn43c799e2003-04-08 00:08:52 +0000687 if (eof || VG_STREQ(buf, "}")) goto syntax_error;
njn25e49d8e72002-09-23 09:36:25 +0000688 supp->sname = VG_(arena_strdup)(VG_AR_CORE, buf);
sewardjde4a1d02002-03-22 01:27:54 +0000689
njn4ba5a792002-09-30 10:23:54 +0000690 eof = VG_(get_line) ( fd, buf, N_BUF );
njn25e49d8e72002-09-23 09:36:25 +0000691
sewardjde4a1d02002-03-22 01:27:54 +0000692 if (eof) goto syntax_error;
sewardjde4a1d02002-03-22 01:27:54 +0000693
njn11cc9252002-10-07 14:42:59 +0000694 /* Check it has the "skin1,skin2,...:supp" form (look for ':') */
njnc40c3a82002-10-02 11:02:27 +0000695 i = 0;
696 while (True) {
697 if (buf[i] == ':') break;
698 if (buf[i] == '\0') goto syntax_error;
699 i++;
njn25e49d8e72002-09-23 09:36:25 +0000700 }
njnc40c3a82002-10-02 11:02:27 +0000701 buf[i] = '\0'; /* Replace ':', splitting into two strings */
702
njn11cc9252002-10-07 14:42:59 +0000703 skin_names = & buf[0];
704 supp_name = & buf[i+1];
njnc40c3a82002-10-02 11:02:27 +0000705
njn11cc9252002-10-07 14:42:59 +0000706 /* Is it a core suppression? */
707 if (VG_(needs).core_errors && skin_name_present("core", skin_names))
njnc40c3a82002-10-02 11:02:27 +0000708 {
njn43c799e2003-04-08 00:08:52 +0000709 if (VG_STREQ(supp_name, "PThread"))
njn810086f2002-11-14 12:42:47 +0000710 supp->skind = PThreadSupp;
njnc40c3a82002-10-02 11:02:27 +0000711 else
712 goto syntax_error;
713 }
714
njn11cc9252002-10-07 14:42:59 +0000715 /* Is it a skin suppression? */
716 else if (VG_(needs).skin_errors &&
717 skin_name_present(VG_(details).name, skin_names))
njnc40c3a82002-10-02 11:02:27 +0000718 {
njn810086f2002-11-14 12:42:47 +0000719 if (SK_(recognised_suppression)(supp_name, supp))
njnc40c3a82002-10-02 11:02:27 +0000720 {
njn810086f2002-11-14 12:42:47 +0000721 /* Do nothing, function fills in supp->skind */
njnc40c3a82002-10-02 11:02:27 +0000722 } else
723 goto syntax_error;
724 }
725
njn25e49d8e72002-09-23 09:36:25 +0000726 else {
njnc40c3a82002-10-02 11:02:27 +0000727 /* Ignore rest of suppression */
njn25e49d8e72002-09-23 09:36:25 +0000728 while (True) {
njn4ba5a792002-09-30 10:23:54 +0000729 eof = VG_(get_line) ( fd, buf, N_BUF );
njn25e49d8e72002-09-23 09:36:25 +0000730 if (eof) goto syntax_error;
njn43c799e2003-04-08 00:08:52 +0000731 if (VG_STREQ(buf, "}"))
njn25e49d8e72002-09-23 09:36:25 +0000732 break;
733 }
734 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000735 }
736
njn25e49d8e72002-09-23 09:36:25 +0000737 if (VG_(needs).skin_errors &&
njn810086f2002-11-14 12:42:47 +0000738 !SK_(read_extra_suppression_info)(fd, buf, N_BUF, supp))
sewardjde4a1d02002-03-22 01:27:54 +0000739 goto syntax_error;
740
njn25e49d8e72002-09-23 09:36:25 +0000741 /* "i > 0" ensures at least one caller read. */
njn633de322003-05-12 20:40:13 +0000742 for (i = 0; i <= VG_N_SUPP_CALLERS; i++) {
njn4ba5a792002-09-30 10:23:54 +0000743 eof = VG_(get_line) ( fd, buf, N_BUF );
sewardjde4a1d02002-03-22 01:27:54 +0000744 if (eof) goto syntax_error;
njn43c799e2003-04-08 00:08:52 +0000745 if (i > 0 && VG_STREQ(buf, "}"))
njn25e49d8e72002-09-23 09:36:25 +0000746 break;
njn633de322003-05-12 20:40:13 +0000747 if (i == VG_N_SUPP_CALLERS)
748 break;
njn25e49d8e72002-09-23 09:36:25 +0000749 supp->caller[i] = VG_(arena_strdup)(VG_AR_CORE, buf);
750 if (!setLocationTy(&(supp->caller[i]), &(supp->caller_ty[i])))
751 goto syntax_error;
sewardjde4a1d02002-03-22 01:27:54 +0000752 }
753
sewardj57a8f5f2003-07-06 01:40:11 +0000754 /* make sure to grab the '}' if the num callers is >=
755 VG_N_SUPP_CALLERS */
756 if (!VG_STREQ(buf, "}")) {
757 do {
758 eof = VG_(get_line) ( fd, buf, N_BUF );
759 } while (!eof && !VG_STREQ(buf, "}"));
760 }
761
sewardjde4a1d02002-03-22 01:27:54 +0000762 supp->next = vg_suppressions;
763 vg_suppressions = supp;
764 }
sewardjde4a1d02002-03-22 01:27:54 +0000765 VG_(close)(fd);
766 return;
767
768 syntax_error:
769 if (eof) {
770 VG_(message)(Vg_UserMsg,
771 "FATAL: in suppressions file `%s': unexpected EOF",
772 filename );
773 } else {
774 VG_(message)(Vg_UserMsg,
njn11cc9252002-10-07 14:42:59 +0000775 "FATAL: in suppressions file: `%s': syntax error on: %s",
sewardjde4a1d02002-03-22 01:27:54 +0000776 filename, buf );
777 }
778 VG_(close)(fd);
779 VG_(message)(Vg_UserMsg, "exiting now.");
780 VG_(exit)(1);
781
782# undef N_BUF
783}
784
785
786void VG_(load_suppressions) ( void )
787{
788 Int i;
789 vg_suppressions = NULL;
790 for (i = 0; i < VG_(clo_n_suppressions); i++) {
791 if (VG_(clo_verbosity) > 1) {
792 VG_(message)(Vg_UserMsg, "Reading suppressions file: %s",
793 VG_(clo_suppressions)[i] );
794 }
795 load_one_suppressions_file( VG_(clo_suppressions)[i] );
796 }
797}
798
njn25e49d8e72002-09-23 09:36:25 +0000799/* Return the name of an erring fn in a way which is useful
800 for comparing against the contents of a suppressions file.
801 Doesn't demangle the fn name, because we want to refer to
802 mangled names in the suppressions file.
sewardj99aac972002-12-26 01:53:45 +0000803*/
njn43c799e2003-04-08 00:08:52 +0000804static void get_objname_fnname ( Addr a, Char* obj_buf, Int n_obj_buf,
805 Char* fun_buf, Int n_fun_buf )
njn25e49d8e72002-09-23 09:36:25 +0000806{
807 (void)VG_(get_objname) ( a, obj_buf, n_obj_buf );
808 (void)VG_(get_fnname_nodemangle)( a, fun_buf, n_fun_buf );
809}
810
811static __inline__
njn810086f2002-11-14 12:42:47 +0000812Bool supp_matches_error(Supp* su, Error* err)
njn25e49d8e72002-09-23 09:36:25 +0000813{
njn810086f2002-11-14 12:42:47 +0000814 switch (su->skind) {
njn25e49d8e72002-09-23 09:36:25 +0000815 case PThreadSupp:
njn810086f2002-11-14 12:42:47 +0000816 return (err->ekind == PThreadErr);
njn25e49d8e72002-09-23 09:36:25 +0000817 default:
818 if (VG_(needs).skin_errors) {
njn810086f2002-11-14 12:42:47 +0000819 return SK_(error_matches_suppression)(err, su);
njn25e49d8e72002-09-23 09:36:25 +0000820 } else {
821 VG_(printf)(
822 "\nUnhandled suppression type: %u. VG_(needs).skin_errors\n"
823 "probably needs to be set.\n",
njn810086f2002-11-14 12:42:47 +0000824 err->ekind);
njne427a662002-10-02 11:08:25 +0000825 VG_(skin_panic)("unhandled suppression type");
njn25e49d8e72002-09-23 09:36:25 +0000826 }
827 }
828}
829
830static __inline__
njn810086f2002-11-14 12:42:47 +0000831Bool supp_matches_callers(Supp* su, Char caller_obj[][M_VG_ERRTXT],
832 Char caller_fun[][M_VG_ERRTXT])
njn25e49d8e72002-09-23 09:36:25 +0000833{
834 Int i;
835
njn633de322003-05-12 20:40:13 +0000836 for (i = 0; i < VG_N_SUPP_CALLERS && su->caller[i] != NULL; i++) {
njn25e49d8e72002-09-23 09:36:25 +0000837 switch (su->caller_ty[i]) {
njn4ba5a792002-09-30 10:23:54 +0000838 case ObjName: if (VG_(string_match)(su->caller[i],
839 caller_obj[i])) break;
njn25e49d8e72002-09-23 09:36:25 +0000840 return False;
njn4ba5a792002-09-30 10:23:54 +0000841 case FunName: if (VG_(string_match)(su->caller[i],
842 caller_fun[i])) break;
njn25e49d8e72002-09-23 09:36:25 +0000843 return False;
njn43c799e2003-04-08 00:08:52 +0000844 default: VG_(skin_panic)("supp_matches_callers");
njn25e49d8e72002-09-23 09:36:25 +0000845 }
846 }
847
848 /* If we reach here, it's a match */
849 return True;
850}
sewardjde4a1d02002-03-22 01:27:54 +0000851
njn810086f2002-11-14 12:42:47 +0000852/* Does an error context match a suppression? ie is this a suppressible
853 error? If so, return a pointer to the Supp record, otherwise NULL.
njn25e49d8e72002-09-23 09:36:25 +0000854 Tries to minimise the number of symbol searches since they are expensive.
sewardjde4a1d02002-03-22 01:27:54 +0000855*/
njn810086f2002-11-14 12:42:47 +0000856static Supp* is_suppressible_error ( Error* err )
sewardjde4a1d02002-03-22 01:27:54 +0000857{
njn25e49d8e72002-09-23 09:36:25 +0000858 Int i;
sewardjde4a1d02002-03-22 01:27:54 +0000859
njn25e49d8e72002-09-23 09:36:25 +0000860 Char caller_obj[VG_N_SUPP_CALLERS][M_VG_ERRTXT];
861 Char caller_fun[VG_N_SUPP_CALLERS][M_VG_ERRTXT];
sewardjde4a1d02002-03-22 01:27:54 +0000862
njn810086f2002-11-14 12:42:47 +0000863 Supp* su;
sewardjde4a1d02002-03-22 01:27:54 +0000864
njn25e49d8e72002-09-23 09:36:25 +0000865 /* get_objname_fnname() writes the function name and object name if
njn43c799e2003-04-08 00:08:52 +0000866 it finds them in the debug info. So the strings in the suppression
njn25e49d8e72002-09-23 09:36:25 +0000867 file should match these.
sewardjde4a1d02002-03-22 01:27:54 +0000868 */
869
870 /* Initialise these strs so they are always safe to compare, even
njn25e49d8e72002-09-23 09:36:25 +0000871 if get_objname_fnname doesn't write anything to them. */
872 for (i = 0; i < VG_N_SUPP_CALLERS; i++)
873 caller_obj[i][0] = caller_fun[i][0] = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000874
njn25e49d8e72002-09-23 09:36:25 +0000875 for (i = 0; i < VG_N_SUPP_CALLERS && i < VG_(clo_backtrace_size); i++) {
njn43c799e2003-04-08 00:08:52 +0000876 get_objname_fnname ( err->where->eips[i], caller_obj[i], M_VG_ERRTXT,
877 caller_fun[i], M_VG_ERRTXT );
sewardjde4a1d02002-03-22 01:27:54 +0000878 }
879
880 /* See if the error context matches any suppression. */
881 for (su = vg_suppressions; su != NULL; su = su->next) {
njn25e49d8e72002-09-23 09:36:25 +0000882 if (supp_matches_error(su, err) &&
883 supp_matches_callers(su, caller_obj, caller_fun)) {
884 return su;
sewardjde4a1d02002-03-22 01:27:54 +0000885 }
sewardjde4a1d02002-03-22 01:27:54 +0000886 }
njn25e49d8e72002-09-23 09:36:25 +0000887 return NULL; /* no matches */
sewardjde4a1d02002-03-22 01:27:54 +0000888}
889
sewardjde4a1d02002-03-22 01:27:54 +0000890/*--------------------------------------------------------------------*/
891/*--- end vg_errcontext.c ---*/
892/*--------------------------------------------------------------------*/