blob: 96fe88a96cbc848e3588edcdf3c745c6d5782484 [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__
njn72718642003-07-24 08:45:32 +0000169void construct_error ( Error* err, ThreadId tid, ErrorKind ekind, Addr a,
170 Char* s, void* extra, ExeContext* where )
sewardjde4a1d02002-03-22 01:27:54 +0000171{
njn72718642003-07-24 08:45:32 +0000172 sk_assert(tid < VG_N_THREADS);
173
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;
njn72718642003-07-24 08:45:32 +0000178 err->tid = tid;
njn43c799e2003-04-08 00:08:52 +0000179 if (NULL == where)
njn72718642003-07-24 08:45:32 +0000180 err->where = VG_(get_ExeContext)( tid );
njn43c799e2003-04-08 00:08:52 +0000181 else
182 err->where = where;
njn1d6c4bc2002-11-21 13:38:08 +0000183
njn810086f2002-11-14 12:42:47 +0000184 /* Skin-relevant parts */
185 err->ekind = ekind;
186 err->addr = a;
njn810086f2002-11-14 12:42:47 +0000187 err->extra = extra;
sewardja6022612003-07-24 23:50:17 +0000188 err->string = s;
189
njn25e49d8e72002-09-23 09:36:25 +0000190 /* sanity... */
njn72718642003-07-24 08:45:32 +0000191 vg_assert( tid < VG_N_THREADS );
njn25e49d8e72002-09-23 09:36:25 +0000192}
193
njn43c799e2003-04-08 00:08:52 +0000194void VG_(gen_suppression)(Error* err)
195{
sewardj05bcdcb2003-05-18 10:05:38 +0000196 Int i;
njn43c799e2003-04-08 00:08:52 +0000197 UChar buf[M_VG_ERRTXT];
198 ExeContext* ec = VG_(get_error_where)(err);
199 Int stop_at = VG_(clo_backtrace_size);
njn43c799e2003-04-08 00:08:52 +0000200
njn633de322003-05-12 20:40:13 +0000201 if (stop_at > 4) stop_at = 4; /* At most four names */
njn43c799e2003-04-08 00:08:52 +0000202 vg_assert(stop_at > 0);
203
204 VG_(printf)("{\n");
205 VG_(printf)(" <insert a suppression name here>\n");
njn6a230532003-07-21 10:38:23 +0000206
207 if (PThreadErr == err->ekind) {
208 VG_(printf)(" core:PThread\n");
209
210 } else {
211 Char* name = SK_(get_error_name)(err);
212 if (NULL == name) {
213 VG_(message)(Vg_UserMsg,
214 "(skin does not allow error to be suppressed)");
215 return;
216 }
217 VG_(printf)(" %s:%s\n", VG_(details).name, name);
218 SK_(print_extra_suppression_info)(err);
219 }
njn43c799e2003-04-08 00:08:52 +0000220
221 /* This loop condensed from VG_(mini_stack_dump)() */
222 i = 0;
223 do {
224 Addr eip = ec->eips[i];
225 if (i > 0)
226 eip--; /* point to calling line */
227
228 if ( VG_(get_fnname_nodemangle) (eip, buf, M_VG_ERRTXT) ) {
229 VG_(printf)(" fun:%s\n", buf);
230 } else if ( VG_(get_objname)(eip, buf, M_VG_ERRTXT) ) {
231 VG_(printf)(" obj:%s\n", buf);
232 } else {
233 VG_(printf)(" ???:??? "
234 "# unknown, suppression will not work, sorry)\n");
235 }
236 i++;
237 } while (i < stop_at && ec->eips[i] != 0);
238
239 VG_(printf)("}\n");
240}
241
njnb4aee052003-04-15 14:09:58 +0000242static
njn72718642003-07-24 08:45:32 +0000243void do_actions_on_error(Error* err, Bool allow_GDB_attach)
njn43c799e2003-04-08 00:08:52 +0000244{
245 /* Perhaps we want a GDB attach at this point? */
njn3e884182003-04-15 13:03:23 +0000246 if (allow_GDB_attach &&
247 VG_(is_action_requested)( "Attach to GDB", & VG_(clo_GDB_attach) ))
248 {
njn72718642003-07-24 08:45:32 +0000249 Addr m_eip, m_esp, m_ebp;
250
251 if (VG_(is_running_thread)( err->tid )) {
252 m_eip = VG_(baseBlock)[VGOFF_(m_eip)];
253 m_esp = VG_(baseBlock)[VGOFF_(m_esp)];
254 m_ebp = VG_(baseBlock)[VGOFF_(m_ebp)];
255 } else {
256 ThreadState* tst = & VG_(threads)[ err->tid ];
257 m_eip = tst->m_eip;
258 m_esp = tst->m_esp;
259 m_ebp = tst->m_ebp;
260 }
njn3e884182003-04-15 13:03:23 +0000261 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. */
njn72718642003-07-24 08:45:32 +0000277void VG_(maybe_record_error) ( ThreadId tid,
njn25e49d8e72002-09-23 09:36:25 +0000278 ErrorKind ekind, Addr a, Char* s, void* extra )
279{
njn810086f2002-11-14 12:42:47 +0000280 Error err;
281 Error* p;
282 Error* p_prev;
njn43c799e2003-04-08 00:08:52 +0000283 UInt extra_size;
njn810086f2002-11-14 12:42:47 +0000284 VgRes exe_res = Vg_MedRes;
njn810086f2002-11-14 12:42:47 +0000285 static Bool stopping_message = False;
286 static Bool slowdown_message = False;
287 static Int vg_n_errs_shown = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000288
sewardjf2537be2002-04-24 21:03:47 +0000289 /* After M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN different errors have
290 been found, or M_VG_COLLECT_NO_ERRORS_AFTER_FOUND total errors
291 have been found, just refuse to collect any more. This stops
292 the burden of the error-management system becoming excessive in
293 extremely buggy programs, although it does make it pretty
294 pointless to continue the Valgrind run after this point. */
sewardj2e432902002-06-13 20:44:00 +0000295 if (VG_(clo_error_limit)
sewardj72f98ff2002-06-13 17:23:38 +0000296 && (vg_n_errs_shown >= M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN
njn47363ab2003-04-21 13:24:40 +0000297 || VG_(n_errs_found) >= M_VG_COLLECT_NO_ERRORS_AFTER_FOUND)) {
sewardjde4a1d02002-03-22 01:27:54 +0000298 if (!stopping_message) {
299 VG_(message)(Vg_UserMsg, "");
sewardjf2537be2002-04-24 21:03:47 +0000300
301 if (vg_n_errs_shown >= M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN) {
302 VG_(message)(Vg_UserMsg,
303 "More than %d different errors detected. "
304 "I'm not reporting any more.",
305 M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN );
306 } else {
307 VG_(message)(Vg_UserMsg,
308 "More than %d total errors detected. "
309 "I'm not reporting any more.",
310 M_VG_COLLECT_NO_ERRORS_AFTER_FOUND );
311 }
312
sewardjde4a1d02002-03-22 01:27:54 +0000313 VG_(message)(Vg_UserMsg,
sewardjf2537be2002-04-24 21:03:47 +0000314 "Final error counts will be inaccurate. Go fix your program!");
sewardj72f98ff2002-06-13 17:23:38 +0000315 VG_(message)(Vg_UserMsg,
sewardj2e432902002-06-13 20:44:00 +0000316 "Rerun with --error-limit=no to disable this cutoff. Note");
sewardj72f98ff2002-06-13 17:23:38 +0000317 VG_(message)(Vg_UserMsg,
njn25e49d8e72002-09-23 09:36:25 +0000318 "that errors may occur in your program without prior warning from");
sewardj72f98ff2002-06-13 17:23:38 +0000319 VG_(message)(Vg_UserMsg,
320 "Valgrind, because errors are no longer being displayed.");
sewardjde4a1d02002-03-22 01:27:54 +0000321 VG_(message)(Vg_UserMsg, "");
322 stopping_message = True;
323 }
324 return;
325 }
326
327 /* After M_VG_COLLECT_ERRORS_SLOWLY_AFTER different errors have
328 been found, be much more conservative about collecting new
329 ones. */
330 if (vg_n_errs_shown >= M_VG_COLLECT_ERRORS_SLOWLY_AFTER) {
njn25e49d8e72002-09-23 09:36:25 +0000331 exe_res = Vg_LowRes;
sewardjde4a1d02002-03-22 01:27:54 +0000332 if (!slowdown_message) {
333 VG_(message)(Vg_UserMsg, "");
334 VG_(message)(Vg_UserMsg,
335 "More than %d errors detected. Subsequent errors",
336 M_VG_COLLECT_ERRORS_SLOWLY_AFTER);
337 VG_(message)(Vg_UserMsg,
338 "will still be recorded, but in less detail than before.");
339 slowdown_message = True;
340 }
341 }
342
njn25e49d8e72002-09-23 09:36:25 +0000343 /* Build ourselves the error */
njn72718642003-07-24 08:45:32 +0000344 construct_error ( &err, tid, ekind, a, s, extra, NULL );
sewardjde4a1d02002-03-22 01:27:54 +0000345
346 /* First, see if we've got an error record matching this one. */
njn25e49d8e72002-09-23 09:36:25 +0000347 p = vg_errors;
sewardjde4a1d02002-03-22 01:27:54 +0000348 p_prev = NULL;
349 while (p != NULL) {
njn810086f2002-11-14 12:42:47 +0000350 if (eq_Error(exe_res, p, &err)) {
sewardjde4a1d02002-03-22 01:27:54 +0000351 /* Found it. */
352 p->count++;
353 if (p->supp != NULL) {
354 /* Deal correctly with suppressed errors. */
355 p->supp->count++;
356 vg_n_errs_suppressed++;
357 } else {
njn47363ab2003-04-21 13:24:40 +0000358 VG_(n_errs_found)++;
sewardjde4a1d02002-03-22 01:27:54 +0000359 }
360
361 /* Move p to the front of the list so that future searches
362 for it are faster. */
363 if (p_prev != NULL) {
364 vg_assert(p_prev->next == p);
365 p_prev->next = p->next;
njn25e49d8e72002-09-23 09:36:25 +0000366 p->next = vg_errors;
367 vg_errors = p;
sewardjde4a1d02002-03-22 01:27:54 +0000368 }
sewardj7ebf7c32003-07-24 21:29:40 +0000369
sewardjde4a1d02002-03-22 01:27:54 +0000370 return;
371 }
372 p_prev = p;
373 p = p->next;
374 }
375
376 /* Didn't see it. Copy and add. */
377
njn43c799e2003-04-08 00:08:52 +0000378 /* OK, we're really going to collect it. The context is on the stack and
379 will disappear shortly, so we must copy it. First do the main
380 (non-`extra') part.
njn25e49d8e72002-09-23 09:36:25 +0000381
njn43c799e2003-04-08 00:08:52 +0000382 Then SK_(update_extra) can update the `extra' part. This is for when
383 there are more details to fill in which take time to work out but
384 don't affect our earlier decision to include the error -- by
njn25e49d8e72002-09-23 09:36:25 +0000385 postponing those details until now, we avoid the extra work in the
njn810086f2002-11-14 12:42:47 +0000386 case where we ignore the error. Ugly.
njn43c799e2003-04-08 00:08:52 +0000387
388 Then, if there is an `extra' part, copy it too, using the size that
njna70114c2003-08-19 16:14:42 +0000389 SK_(update_extra) returned. Also allow for people using the void*
390 extra field for a scalar value like an integer.
njn43c799e2003-04-08 00:08:52 +0000391 */
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') */
njna70114c2003-08-19 16:14:42 +0000398 if (VG_(needs).skin_errors && PThreadErr != ekind) {
njn6a230532003-07-21 10:38:23 +0000399 extra_size = SK_(update_extra)(p);
njn43c799e2003-04-08 00:08:52 +0000400
njna70114c2003-08-19 16:14:42 +0000401 /* copy block pointed to by `extra', if there is one */
402 if (NULL != p->extra && 0 != extra_size) {
njn6a230532003-07-21 10:38:23 +0000403 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++;
njn72718642003-07-24 08:45:32 +0000419 do_actions_on_error(p, /*allow_GDB_attach*/True);
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*/
njn72718642003-07-24 08:45:32 +0000433Bool VG_(unique_error) ( ThreadId tid, 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;
438
439 /* Build ourselves the error */
njn72718642003-07-24 08:45:32 +0000440 construct_error ( &err, tid, ekind, a, s, extra, where );
njn43c799e2003-04-08 00:08:52 +0000441
442 /* Unless it's suppressed, we're going to show it. Don't need to make
443 a copy, because it's only temporary anyway.
444
445 Then update the `extra' part with SK_(update_extra), because that can
446 have an affect on whether it's suppressed. Ignore the size return
447 value of SK_(update_extra), because we're not copying `extra'. */
448 (void)SK_(update_extra)(&err);
449
450 if (NULL == is_suppressible_error(&err)) {
njn47363ab2003-04-21 13:24:40 +0000451 if (count_error)
452 VG_(n_errs_found)++;
njn43c799e2003-04-08 00:08:52 +0000453
454 if (print_error) {
455 if (!is_first_shown_context)
456 VG_(message)(Vg_UserMsg, "");
457 pp_Error(&err, False);
458 is_first_shown_context = False;
459 }
njn72718642003-07-24 08:45:32 +0000460 do_actions_on_error(&err, allow_GDB_attach);
njn43c799e2003-04-08 00:08:52 +0000461
462 return False;
463
464 } else {
465 vg_n_errs_suppressed++;
466 return True;
467 }
468}
469
sewardjde4a1d02002-03-22 01:27:54 +0000470
sewardjde4a1d02002-03-22 01:27:54 +0000471/*------------------------------------------------------------*/
472/*--- Exported fns ---*/
473/*------------------------------------------------------------*/
474
njn25e49d8e72002-09-23 09:36:25 +0000475/* These are called not from generated code but from the scheduler */
sewardj8c824512002-04-14 04:16:48 +0000476
njn25e49d8e72002-09-23 09:36:25 +0000477void VG_(record_pthread_error) ( ThreadId tid, Char* msg )
sewardjde4a1d02002-03-22 01:27:54 +0000478{
njn25e49d8e72002-09-23 09:36:25 +0000479 if (! VG_(needs).core_errors) return;
njn72718642003-07-24 08:45:32 +0000480 VG_(maybe_record_error)( tid, PThreadErr, /*addr*/0, msg, /*extra*/NULL );
sewardjde4a1d02002-03-22 01:27:54 +0000481}
482
sewardj8c824512002-04-14 04:16:48 +0000483/*------------------------------*/
484
sewardjde4a1d02002-03-22 01:27:54 +0000485void VG_(show_all_errors) ( void )
486{
njn810086f2002-11-14 12:42:47 +0000487 Int i, n_min;
488 Int n_err_contexts, n_supp_contexts;
489 Error *p, *p_min;
490 Supp *su;
491 Bool any_supp;
sewardjde4a1d02002-03-22 01:27:54 +0000492
493 if (VG_(clo_verbosity) == 0)
494 return;
495
496 n_err_contexts = 0;
njn25e49d8e72002-09-23 09:36:25 +0000497 for (p = vg_errors; p != NULL; p = p->next) {
sewardjde4a1d02002-03-22 01:27:54 +0000498 if (p->supp == NULL)
499 n_err_contexts++;
500 }
501
502 n_supp_contexts = 0;
503 for (su = vg_suppressions; su != NULL; su = su->next) {
504 if (su->count > 0)
505 n_supp_contexts++;
506 }
sewardjde4a1d02002-03-22 01:27:54 +0000507 VG_(message)(Vg_UserMsg,
508 "ERROR SUMMARY: "
509 "%d errors from %d contexts (suppressed: %d from %d)",
njn47363ab2003-04-21 13:24:40 +0000510 VG_(n_errs_found), n_err_contexts,
sewardjde4a1d02002-03-22 01:27:54 +0000511 vg_n_errs_suppressed, n_supp_contexts );
512
513 if (VG_(clo_verbosity) <= 1)
514 return;
515
516 /* Print the contexts in order of increasing error count. */
517 for (i = 0; i < n_err_contexts; i++) {
518 n_min = (1 << 30) - 1;
519 p_min = NULL;
njn25e49d8e72002-09-23 09:36:25 +0000520 for (p = vg_errors; p != NULL; p = p->next) {
sewardjde4a1d02002-03-22 01:27:54 +0000521 if (p->supp != NULL) continue;
522 if (p->count < n_min) {
523 n_min = p->count;
524 p_min = p;
525 }
526 }
njne427a662002-10-02 11:08:25 +0000527 if (p_min == NULL) VG_(skin_panic)("show_all_errors()");
sewardjde4a1d02002-03-22 01:27:54 +0000528
529 VG_(message)(Vg_UserMsg, "");
530 VG_(message)(Vg_UserMsg, "%d errors in context %d of %d:",
531 p_min->count,
532 i+1, n_err_contexts);
njn810086f2002-11-14 12:42:47 +0000533 pp_Error( p_min, False );
sewardjde4a1d02002-03-22 01:27:54 +0000534
535 if ((i+1 == VG_(clo_dump_error))) {
sewardj1e8cdc92002-04-18 11:37:52 +0000536 VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to below NULLs */,
sewardj22854b92002-11-30 14:00:47 +0000537 p_min->where->eips[0], NULL, NULL, NULL, NULL );
sewardjde4a1d02002-03-22 01:27:54 +0000538 }
539
540 p_min->count = 1 << 30;
541 }
542
543 if (n_supp_contexts > 0)
544 VG_(message)(Vg_DebugMsg, "");
545 any_supp = False;
546 for (su = vg_suppressions; su != NULL; su = su->next) {
547 if (su->count > 0) {
548 any_supp = True;
njn25e49d8e72002-09-23 09:36:25 +0000549 VG_(message)(Vg_DebugMsg, "supp: %4d %s", su->count, su->sname);
sewardjde4a1d02002-03-22 01:27:54 +0000550 }
551 }
552
553 if (n_err_contexts > 0) {
554 if (any_supp)
555 VG_(message)(Vg_UserMsg, "");
556 VG_(message)(Vg_UserMsg,
557 "IN SUMMARY: "
558 "%d errors from %d contexts (suppressed: %d from %d)",
njn47363ab2003-04-21 13:24:40 +0000559 VG_(n_errs_found), n_err_contexts,
sewardjde4a1d02002-03-22 01:27:54 +0000560 vg_n_errs_suppressed,
561 n_supp_contexts );
562 VG_(message)(Vg_UserMsg, "");
563 }
564}
565
566/*------------------------------------------------------------*/
567/*--- Standard suppressions ---*/
568/*------------------------------------------------------------*/
569
570/* Get a non-blank, non-comment line of at most nBuf chars from fd.
571 Skips leading spaces on the line. Return True if EOF was hit instead.
572*/
573
574#define VG_ISSPACE(ch) (((ch)==' ') || ((ch)=='\n') || ((ch)=='\t'))
575
njn4ba5a792002-09-30 10:23:54 +0000576Bool VG_(get_line) ( Int fd, Char* buf, Int nBuf )
sewardjde4a1d02002-03-22 01:27:54 +0000577{
578 Char ch;
579 Int n, i;
580 while (True) {
581 /* First, read until a non-blank char appears. */
582 while (True) {
583 n = VG_(read)(fd, &ch, 1);
584 if (n == 1 && !VG_ISSPACE(ch)) break;
585 if (n == 0) return True;
586 }
587
588 /* Now, read the line into buf. */
589 i = 0;
590 buf[i++] = ch; buf[i] = 0;
591 while (True) {
592 n = VG_(read)(fd, &ch, 1);
593 if (n == 0) return False; /* the next call will return True */
594 if (ch == '\n') break;
595 if (i > 0 && i == nBuf-1) i--;
596 buf[i++] = ch; buf[i] = 0;
597 }
598 while (i > 1 && VG_ISSPACE(buf[i-1])) {
599 i--; buf[i] = 0;
600 };
601
602 /* VG_(printf)("The line is `%s'\n", buf); */
603 /* Ok, we have a line. If a non-comment line, return.
604 If a comment line, start all over again. */
605 if (buf[0] != '#') return False;
606 }
607}
608
609
610/* *p_caller contains the raw name of a caller, supposedly either
611 fun:some_function_name or
612 obj:some_object_name.
613 Set *p_ty accordingly and advance *p_caller over the descriptor
614 (fun: or obj:) part.
615 Returns False if failed.
616*/
njn25e49d8e72002-09-23 09:36:25 +0000617static Bool setLocationTy ( Char** p_caller, SuppLocTy* p_ty )
sewardjde4a1d02002-03-22 01:27:54 +0000618{
619 if (VG_(strncmp)(*p_caller, "fun:", 4) == 0) {
620 (*p_caller) += 4;
621 *p_ty = FunName;
622 return True;
623 }
624 if (VG_(strncmp)(*p_caller, "obj:", 4) == 0) {
625 (*p_caller) += 4;
626 *p_ty = ObjName;
627 return True;
628 }
629 VG_(printf)("location should start with fun: or obj:\n");
630 return False;
631}
632
633
njn11cc9252002-10-07 14:42:59 +0000634/* Look for "skin" in a string like "skin1,skin2,skin3" */
635static __inline__
636Bool skin_name_present(Char *name, Char *names)
637{
638 Bool found;
639 Char *s = NULL; /* Shut gcc up */
640 Int len = VG_(strlen)(name);
641
642 found = (NULL != (s = VG_(strstr)(names, name)) &&
643 (s == names || *(s-1) == ',') &&
644 (*(s+len) == ',' || *(s+len) == '\0')
645 );
646
647 return found;
648}
649
sewardjde4a1d02002-03-22 01:27:54 +0000650/* Read suppressions from the file specified in vg_clo_suppressions
651 and place them in the suppressions list. If there's any difficulty
652 doing this, just give up -- there's no point in trying to recover.
653*/
sewardjde4a1d02002-03-22 01:27:54 +0000654static void load_one_suppressions_file ( Char* filename )
655{
656# define N_BUF 200
njnc40c3a82002-10-02 11:02:27 +0000657 Int fd, i;
658 Bool eof;
659 Char buf[N_BUF+1];
njn11cc9252002-10-07 14:42:59 +0000660 Char* skin_names;
njnc40c3a82002-10-02 11:02:27 +0000661 Char* supp_name;
662
njn25e49d8e72002-09-23 09:36:25 +0000663 fd = VG_(open)( filename, VKI_O_RDONLY, 0 );
sewardjde4a1d02002-03-22 01:27:54 +0000664 if (fd == -1) {
njn25e49d8e72002-09-23 09:36:25 +0000665 VG_(message)(Vg_UserMsg, "FATAL: can't open suppressions file `%s'",
sewardjde4a1d02002-03-22 01:27:54 +0000666 filename );
667 VG_(exit)(1);
668 }
669
670 while (True) {
njn25e49d8e72002-09-23 09:36:25 +0000671 /* Assign and initialise the two suppression halves (core and skin) */
njn810086f2002-11-14 12:42:47 +0000672 Supp* supp;
673 supp = VG_(arena_malloc)(VG_AR_CORE, sizeof(Supp));
sewardjde4a1d02002-03-22 01:27:54 +0000674 supp->count = 0;
njn25e49d8e72002-09-23 09:36:25 +0000675 for (i = 0; i < VG_N_SUPP_CALLERS; i++) supp->caller[i] = NULL;
njn810086f2002-11-14 12:42:47 +0000676 supp->string = supp->extra = NULL;
sewardjde4a1d02002-03-22 01:27:54 +0000677
njn4ba5a792002-09-30 10:23:54 +0000678 eof = VG_(get_line) ( fd, buf, N_BUF );
sewardjde4a1d02002-03-22 01:27:54 +0000679 if (eof) break;
680
njn43c799e2003-04-08 00:08:52 +0000681 if (!VG_STREQ(buf, "{")) goto syntax_error;
sewardjde4a1d02002-03-22 01:27:54 +0000682
njn4ba5a792002-09-30 10:23:54 +0000683 eof = VG_(get_line) ( fd, buf, N_BUF );
njn43c799e2003-04-08 00:08:52 +0000684 if (eof || VG_STREQ(buf, "}")) goto syntax_error;
njn25e49d8e72002-09-23 09:36:25 +0000685 supp->sname = VG_(arena_strdup)(VG_AR_CORE, buf);
sewardjde4a1d02002-03-22 01:27:54 +0000686
njn4ba5a792002-09-30 10:23:54 +0000687 eof = VG_(get_line) ( fd, buf, N_BUF );
njn25e49d8e72002-09-23 09:36:25 +0000688
sewardjde4a1d02002-03-22 01:27:54 +0000689 if (eof) goto syntax_error;
sewardjde4a1d02002-03-22 01:27:54 +0000690
njn11cc9252002-10-07 14:42:59 +0000691 /* Check it has the "skin1,skin2,...:supp" form (look for ':') */
njnc40c3a82002-10-02 11:02:27 +0000692 i = 0;
693 while (True) {
694 if (buf[i] == ':') break;
695 if (buf[i] == '\0') goto syntax_error;
696 i++;
njn25e49d8e72002-09-23 09:36:25 +0000697 }
njnc40c3a82002-10-02 11:02:27 +0000698 buf[i] = '\0'; /* Replace ':', splitting into two strings */
699
njn11cc9252002-10-07 14:42:59 +0000700 skin_names = & buf[0];
701 supp_name = & buf[i+1];
njnc40c3a82002-10-02 11:02:27 +0000702
njn11cc9252002-10-07 14:42:59 +0000703 /* Is it a core suppression? */
704 if (VG_(needs).core_errors && skin_name_present("core", skin_names))
njnc40c3a82002-10-02 11:02:27 +0000705 {
njn43c799e2003-04-08 00:08:52 +0000706 if (VG_STREQ(supp_name, "PThread"))
njn810086f2002-11-14 12:42:47 +0000707 supp->skind = PThreadSupp;
njnc40c3a82002-10-02 11:02:27 +0000708 else
709 goto syntax_error;
710 }
711
njn11cc9252002-10-07 14:42:59 +0000712 /* Is it a skin suppression? */
713 else if (VG_(needs).skin_errors &&
714 skin_name_present(VG_(details).name, skin_names))
njnc40c3a82002-10-02 11:02:27 +0000715 {
njn810086f2002-11-14 12:42:47 +0000716 if (SK_(recognised_suppression)(supp_name, supp))
njnc40c3a82002-10-02 11:02:27 +0000717 {
njn810086f2002-11-14 12:42:47 +0000718 /* Do nothing, function fills in supp->skind */
njnc40c3a82002-10-02 11:02:27 +0000719 } else
720 goto syntax_error;
721 }
722
njn25e49d8e72002-09-23 09:36:25 +0000723 else {
njnc40c3a82002-10-02 11:02:27 +0000724 /* Ignore rest of suppression */
njn25e49d8e72002-09-23 09:36:25 +0000725 while (True) {
njn4ba5a792002-09-30 10:23:54 +0000726 eof = VG_(get_line) ( fd, buf, N_BUF );
njn25e49d8e72002-09-23 09:36:25 +0000727 if (eof) goto syntax_error;
njn43c799e2003-04-08 00:08:52 +0000728 if (VG_STREQ(buf, "}"))
njn25e49d8e72002-09-23 09:36:25 +0000729 break;
730 }
731 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000732 }
733
njn25e49d8e72002-09-23 09:36:25 +0000734 if (VG_(needs).skin_errors &&
njn810086f2002-11-14 12:42:47 +0000735 !SK_(read_extra_suppression_info)(fd, buf, N_BUF, supp))
sewardjde4a1d02002-03-22 01:27:54 +0000736 goto syntax_error;
737
njn25e49d8e72002-09-23 09:36:25 +0000738 /* "i > 0" ensures at least one caller read. */
njn633de322003-05-12 20:40:13 +0000739 for (i = 0; i <= VG_N_SUPP_CALLERS; i++) {
njn4ba5a792002-09-30 10:23:54 +0000740 eof = VG_(get_line) ( fd, buf, N_BUF );
sewardjde4a1d02002-03-22 01:27:54 +0000741 if (eof) goto syntax_error;
njn43c799e2003-04-08 00:08:52 +0000742 if (i > 0 && VG_STREQ(buf, "}"))
njn25e49d8e72002-09-23 09:36:25 +0000743 break;
njn633de322003-05-12 20:40:13 +0000744 if (i == VG_N_SUPP_CALLERS)
745 break;
njn25e49d8e72002-09-23 09:36:25 +0000746 supp->caller[i] = VG_(arena_strdup)(VG_AR_CORE, buf);
747 if (!setLocationTy(&(supp->caller[i]), &(supp->caller_ty[i])))
748 goto syntax_error;
sewardjde4a1d02002-03-22 01:27:54 +0000749 }
750
sewardj57a8f5f2003-07-06 01:40:11 +0000751 /* make sure to grab the '}' if the num callers is >=
752 VG_N_SUPP_CALLERS */
753 if (!VG_STREQ(buf, "}")) {
754 do {
755 eof = VG_(get_line) ( fd, buf, N_BUF );
756 } while (!eof && !VG_STREQ(buf, "}"));
757 }
758
sewardjde4a1d02002-03-22 01:27:54 +0000759 supp->next = vg_suppressions;
760 vg_suppressions = supp;
761 }
sewardjde4a1d02002-03-22 01:27:54 +0000762 VG_(close)(fd);
763 return;
764
765 syntax_error:
766 if (eof) {
767 VG_(message)(Vg_UserMsg,
768 "FATAL: in suppressions file `%s': unexpected EOF",
769 filename );
770 } else {
771 VG_(message)(Vg_UserMsg,
njn11cc9252002-10-07 14:42:59 +0000772 "FATAL: in suppressions file: `%s': syntax error on: %s",
sewardjde4a1d02002-03-22 01:27:54 +0000773 filename, buf );
774 }
775 VG_(close)(fd);
776 VG_(message)(Vg_UserMsg, "exiting now.");
777 VG_(exit)(1);
778
779# undef N_BUF
780}
781
782
783void VG_(load_suppressions) ( void )
784{
785 Int i;
786 vg_suppressions = NULL;
787 for (i = 0; i < VG_(clo_n_suppressions); i++) {
788 if (VG_(clo_verbosity) > 1) {
789 VG_(message)(Vg_UserMsg, "Reading suppressions file: %s",
790 VG_(clo_suppressions)[i] );
791 }
792 load_one_suppressions_file( VG_(clo_suppressions)[i] );
793 }
794}
795
njn25e49d8e72002-09-23 09:36:25 +0000796/* Return the name of an erring fn in a way which is useful
797 for comparing against the contents of a suppressions file.
798 Doesn't demangle the fn name, because we want to refer to
799 mangled names in the suppressions file.
sewardj99aac972002-12-26 01:53:45 +0000800*/
njn43c799e2003-04-08 00:08:52 +0000801static void get_objname_fnname ( Addr a, Char* obj_buf, Int n_obj_buf,
802 Char* fun_buf, Int n_fun_buf )
njn25e49d8e72002-09-23 09:36:25 +0000803{
804 (void)VG_(get_objname) ( a, obj_buf, n_obj_buf );
805 (void)VG_(get_fnname_nodemangle)( a, fun_buf, n_fun_buf );
806}
807
808static __inline__
njn810086f2002-11-14 12:42:47 +0000809Bool supp_matches_error(Supp* su, Error* err)
njn25e49d8e72002-09-23 09:36:25 +0000810{
njn810086f2002-11-14 12:42:47 +0000811 switch (su->skind) {
njn25e49d8e72002-09-23 09:36:25 +0000812 case PThreadSupp:
njn810086f2002-11-14 12:42:47 +0000813 return (err->ekind == PThreadErr);
njn25e49d8e72002-09-23 09:36:25 +0000814 default:
815 if (VG_(needs).skin_errors) {
njn810086f2002-11-14 12:42:47 +0000816 return SK_(error_matches_suppression)(err, su);
njn25e49d8e72002-09-23 09:36:25 +0000817 } else {
818 VG_(printf)(
819 "\nUnhandled suppression type: %u. VG_(needs).skin_errors\n"
820 "probably needs to be set.\n",
njn810086f2002-11-14 12:42:47 +0000821 err->ekind);
njne427a662002-10-02 11:08:25 +0000822 VG_(skin_panic)("unhandled suppression type");
njn25e49d8e72002-09-23 09:36:25 +0000823 }
824 }
825}
826
827static __inline__
njn810086f2002-11-14 12:42:47 +0000828Bool supp_matches_callers(Supp* su, Char caller_obj[][M_VG_ERRTXT],
829 Char caller_fun[][M_VG_ERRTXT])
njn25e49d8e72002-09-23 09:36:25 +0000830{
831 Int i;
832
njn633de322003-05-12 20:40:13 +0000833 for (i = 0; i < VG_N_SUPP_CALLERS && su->caller[i] != NULL; i++) {
njn25e49d8e72002-09-23 09:36:25 +0000834 switch (su->caller_ty[i]) {
njn4ba5a792002-09-30 10:23:54 +0000835 case ObjName: if (VG_(string_match)(su->caller[i],
836 caller_obj[i])) break;
njn25e49d8e72002-09-23 09:36:25 +0000837 return False;
njn4ba5a792002-09-30 10:23:54 +0000838 case FunName: if (VG_(string_match)(su->caller[i],
839 caller_fun[i])) break;
njn25e49d8e72002-09-23 09:36:25 +0000840 return False;
njn43c799e2003-04-08 00:08:52 +0000841 default: VG_(skin_panic)("supp_matches_callers");
njn25e49d8e72002-09-23 09:36:25 +0000842 }
843 }
844
845 /* If we reach here, it's a match */
846 return True;
847}
sewardjde4a1d02002-03-22 01:27:54 +0000848
njn810086f2002-11-14 12:42:47 +0000849/* Does an error context match a suppression? ie is this a suppressible
850 error? If so, return a pointer to the Supp record, otherwise NULL.
njn25e49d8e72002-09-23 09:36:25 +0000851 Tries to minimise the number of symbol searches since they are expensive.
sewardjde4a1d02002-03-22 01:27:54 +0000852*/
njn810086f2002-11-14 12:42:47 +0000853static Supp* is_suppressible_error ( Error* err )
sewardjde4a1d02002-03-22 01:27:54 +0000854{
njn25e49d8e72002-09-23 09:36:25 +0000855 Int i;
sewardjde4a1d02002-03-22 01:27:54 +0000856
njn25e49d8e72002-09-23 09:36:25 +0000857 Char caller_obj[VG_N_SUPP_CALLERS][M_VG_ERRTXT];
858 Char caller_fun[VG_N_SUPP_CALLERS][M_VG_ERRTXT];
sewardjde4a1d02002-03-22 01:27:54 +0000859
njn810086f2002-11-14 12:42:47 +0000860 Supp* su;
sewardjde4a1d02002-03-22 01:27:54 +0000861
njn25e49d8e72002-09-23 09:36:25 +0000862 /* get_objname_fnname() writes the function name and object name if
njn43c799e2003-04-08 00:08:52 +0000863 it finds them in the debug info. So the strings in the suppression
njn25e49d8e72002-09-23 09:36:25 +0000864 file should match these.
sewardjde4a1d02002-03-22 01:27:54 +0000865 */
866
867 /* Initialise these strs so they are always safe to compare, even
njn25e49d8e72002-09-23 09:36:25 +0000868 if get_objname_fnname doesn't write anything to them. */
869 for (i = 0; i < VG_N_SUPP_CALLERS; i++)
870 caller_obj[i][0] = caller_fun[i][0] = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000871
njn25e49d8e72002-09-23 09:36:25 +0000872 for (i = 0; i < VG_N_SUPP_CALLERS && i < VG_(clo_backtrace_size); i++) {
njn43c799e2003-04-08 00:08:52 +0000873 get_objname_fnname ( err->where->eips[i], caller_obj[i], M_VG_ERRTXT,
874 caller_fun[i], M_VG_ERRTXT );
sewardjde4a1d02002-03-22 01:27:54 +0000875 }
876
877 /* See if the error context matches any suppression. */
878 for (su = vg_suppressions; su != NULL; su = su->next) {
njn25e49d8e72002-09-23 09:36:25 +0000879 if (supp_matches_error(su, err) &&
880 supp_matches_callers(su, caller_obj, caller_fun)) {
881 return su;
sewardjde4a1d02002-03-22 01:27:54 +0000882 }
sewardjde4a1d02002-03-22 01:27:54 +0000883 }
njn25e49d8e72002-09-23 09:36:25 +0000884 return NULL; /* no matches */
sewardjde4a1d02002-03-22 01:27:54 +0000885}
886
sewardjde4a1d02002-03-22 01:27:54 +0000887/*--------------------------------------------------------------------*/
888/*--- end vg_errcontext.c ---*/
889/*--------------------------------------------------------------------*/