blob: 19f86ff4877b3bd58ba9b7a1622eedeee6fad2ce [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
389 SK_(update_extra) returned.
390 */
391
392 /* copy main part */
njn810086f2002-11-14 12:42:47 +0000393 p = VG_(arena_malloc)(VG_AR_ERRORS, sizeof(Error));
njn25e49d8e72002-09-23 09:36:25 +0000394 *p = err;
njn43c799e2003-04-08 00:08:52 +0000395
njn6a230532003-07-21 10:38:23 +0000396 /* update `extra', for non-core errors (core ones don't use 'extra') */
397 if (VG_(needs).skin_errors) {
398 extra_size = SK_(update_extra)(p);
njn43c799e2003-04-08 00:08:52 +0000399
njn6a230532003-07-21 10:38:23 +0000400 /* copy `extra' if there is one */
401 if (NULL != p->extra) {
402 void* new_extra = VG_(malloc)(extra_size);
403 VG_(memcpy)(new_extra, p->extra, extra_size);
404 p->extra = new_extra;
405 }
njn43c799e2003-04-08 00:08:52 +0000406 }
407
njn25e49d8e72002-09-23 09:36:25 +0000408 p->next = vg_errors;
409 p->supp = is_suppressible_error(&err);
410 vg_errors = p;
sewardjde4a1d02002-03-22 01:27:54 +0000411 if (p->supp == NULL) {
njn47363ab2003-04-21 13:24:40 +0000412 VG_(n_errs_found)++;
sewardjde4a1d02002-03-22 01:27:54 +0000413 if (!is_first_shown_context)
414 VG_(message)(Vg_UserMsg, "");
njn43c799e2003-04-08 00:08:52 +0000415 pp_Error(p, False);
sewardjde4a1d02002-03-22 01:27:54 +0000416 is_first_shown_context = False;
417 vg_n_errs_shown++;
njn72718642003-07-24 08:45:32 +0000418 do_actions_on_error(p, /*allow_GDB_attach*/True);
sewardjde4a1d02002-03-22 01:27:54 +0000419 } else {
420 vg_n_errs_suppressed++;
421 p->supp->count++;
422 }
423}
424
njn43c799e2003-04-08 00:08:52 +0000425/* Second top-level entry point to the error management subsystem, for
426 errors that the skin want to report immediately, eg. because they're
427 guaranteed to only happen once. This avoids all the recording and
428 comparing stuff. But they can be suppressed; returns True if it is
njn47363ab2003-04-21 13:24:40 +0000429 suppressed. Bool `print_error' dictates whether to print the error.
430 Bool `count_error' dictates whether to count the error in VG_(n_errs_found)
431*/
njn72718642003-07-24 08:45:32 +0000432Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind, Addr a, Char* s,
njn3e884182003-04-15 13:03:23 +0000433 void* extra, ExeContext* where, Bool print_error,
njn47363ab2003-04-21 13:24:40 +0000434 Bool allow_GDB_attach, Bool count_error )
njn43c799e2003-04-08 00:08:52 +0000435{
436 Error err;
437
438 /* Build ourselves the error */
njn72718642003-07-24 08:45:32 +0000439 construct_error ( &err, tid, ekind, a, s, extra, where );
njn43c799e2003-04-08 00:08:52 +0000440
441 /* Unless it's suppressed, we're going to show it. Don't need to make
442 a copy, because it's only temporary anyway.
443
444 Then update the `extra' part with SK_(update_extra), because that can
445 have an affect on whether it's suppressed. Ignore the size return
446 value of SK_(update_extra), because we're not copying `extra'. */
447 (void)SK_(update_extra)(&err);
448
449 if (NULL == is_suppressible_error(&err)) {
njn47363ab2003-04-21 13:24:40 +0000450 if (count_error)
451 VG_(n_errs_found)++;
njn43c799e2003-04-08 00:08:52 +0000452
453 if (print_error) {
454 if (!is_first_shown_context)
455 VG_(message)(Vg_UserMsg, "");
456 pp_Error(&err, False);
457 is_first_shown_context = False;
458 }
njn72718642003-07-24 08:45:32 +0000459 do_actions_on_error(&err, allow_GDB_attach);
njn43c799e2003-04-08 00:08:52 +0000460
461 return False;
462
463 } else {
464 vg_n_errs_suppressed++;
465 return True;
466 }
467}
468
sewardjde4a1d02002-03-22 01:27:54 +0000469
sewardjde4a1d02002-03-22 01:27:54 +0000470/*------------------------------------------------------------*/
471/*--- Exported fns ---*/
472/*------------------------------------------------------------*/
473
njn25e49d8e72002-09-23 09:36:25 +0000474/* These are called not from generated code but from the scheduler */
sewardj8c824512002-04-14 04:16:48 +0000475
njn25e49d8e72002-09-23 09:36:25 +0000476void VG_(record_pthread_error) ( ThreadId tid, Char* msg )
sewardjde4a1d02002-03-22 01:27:54 +0000477{
njn25e49d8e72002-09-23 09:36:25 +0000478 if (! VG_(needs).core_errors) return;
njn72718642003-07-24 08:45:32 +0000479 VG_(maybe_record_error)( tid, PThreadErr, /*addr*/0, msg, /*extra*/NULL );
sewardjde4a1d02002-03-22 01:27:54 +0000480}
481
sewardj8c824512002-04-14 04:16:48 +0000482/*------------------------------*/
483
sewardjde4a1d02002-03-22 01:27:54 +0000484void VG_(show_all_errors) ( void )
485{
njn810086f2002-11-14 12:42:47 +0000486 Int i, n_min;
487 Int n_err_contexts, n_supp_contexts;
488 Error *p, *p_min;
489 Supp *su;
490 Bool any_supp;
sewardjde4a1d02002-03-22 01:27:54 +0000491
492 if (VG_(clo_verbosity) == 0)
493 return;
494
495 n_err_contexts = 0;
njn25e49d8e72002-09-23 09:36:25 +0000496 for (p = vg_errors; p != NULL; p = p->next) {
sewardjde4a1d02002-03-22 01:27:54 +0000497 if (p->supp == NULL)
498 n_err_contexts++;
499 }
500
501 n_supp_contexts = 0;
502 for (su = vg_suppressions; su != NULL; su = su->next) {
503 if (su->count > 0)
504 n_supp_contexts++;
505 }
sewardjde4a1d02002-03-22 01:27:54 +0000506 VG_(message)(Vg_UserMsg,
507 "ERROR SUMMARY: "
508 "%d errors from %d contexts (suppressed: %d from %d)",
njn47363ab2003-04-21 13:24:40 +0000509 VG_(n_errs_found), n_err_contexts,
sewardjde4a1d02002-03-22 01:27:54 +0000510 vg_n_errs_suppressed, n_supp_contexts );
511
512 if (VG_(clo_verbosity) <= 1)
513 return;
514
515 /* Print the contexts in order of increasing error count. */
516 for (i = 0; i < n_err_contexts; i++) {
517 n_min = (1 << 30) - 1;
518 p_min = NULL;
njn25e49d8e72002-09-23 09:36:25 +0000519 for (p = vg_errors; p != NULL; p = p->next) {
sewardjde4a1d02002-03-22 01:27:54 +0000520 if (p->supp != NULL) continue;
521 if (p->count < n_min) {
522 n_min = p->count;
523 p_min = p;
524 }
525 }
njne427a662002-10-02 11:08:25 +0000526 if (p_min == NULL) VG_(skin_panic)("show_all_errors()");
sewardjde4a1d02002-03-22 01:27:54 +0000527
528 VG_(message)(Vg_UserMsg, "");
529 VG_(message)(Vg_UserMsg, "%d errors in context %d of %d:",
530 p_min->count,
531 i+1, n_err_contexts);
njn810086f2002-11-14 12:42:47 +0000532 pp_Error( p_min, False );
sewardjde4a1d02002-03-22 01:27:54 +0000533
534 if ((i+1 == VG_(clo_dump_error))) {
sewardj1e8cdc92002-04-18 11:37:52 +0000535 VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to below NULLs */,
sewardj22854b92002-11-30 14:00:47 +0000536 p_min->where->eips[0], NULL, NULL, NULL, NULL );
sewardjde4a1d02002-03-22 01:27:54 +0000537 }
538
539 p_min->count = 1 << 30;
540 }
541
542 if (n_supp_contexts > 0)
543 VG_(message)(Vg_DebugMsg, "");
544 any_supp = False;
545 for (su = vg_suppressions; su != NULL; su = su->next) {
546 if (su->count > 0) {
547 any_supp = True;
njn25e49d8e72002-09-23 09:36:25 +0000548 VG_(message)(Vg_DebugMsg, "supp: %4d %s", su->count, su->sname);
sewardjde4a1d02002-03-22 01:27:54 +0000549 }
550 }
551
552 if (n_err_contexts > 0) {
553 if (any_supp)
554 VG_(message)(Vg_UserMsg, "");
555 VG_(message)(Vg_UserMsg,
556 "IN SUMMARY: "
557 "%d errors from %d contexts (suppressed: %d from %d)",
njn47363ab2003-04-21 13:24:40 +0000558 VG_(n_errs_found), n_err_contexts,
sewardjde4a1d02002-03-22 01:27:54 +0000559 vg_n_errs_suppressed,
560 n_supp_contexts );
561 VG_(message)(Vg_UserMsg, "");
562 }
563}
564
565/*------------------------------------------------------------*/
566/*--- Standard suppressions ---*/
567/*------------------------------------------------------------*/
568
569/* Get a non-blank, non-comment line of at most nBuf chars from fd.
570 Skips leading spaces on the line. Return True if EOF was hit instead.
571*/
572
573#define VG_ISSPACE(ch) (((ch)==' ') || ((ch)=='\n') || ((ch)=='\t'))
574
njn4ba5a792002-09-30 10:23:54 +0000575Bool VG_(get_line) ( Int fd, Char* buf, Int nBuf )
sewardjde4a1d02002-03-22 01:27:54 +0000576{
577 Char ch;
578 Int n, i;
579 while (True) {
580 /* First, read until a non-blank char appears. */
581 while (True) {
582 n = VG_(read)(fd, &ch, 1);
583 if (n == 1 && !VG_ISSPACE(ch)) break;
584 if (n == 0) return True;
585 }
586
587 /* Now, read the line into buf. */
588 i = 0;
589 buf[i++] = ch; buf[i] = 0;
590 while (True) {
591 n = VG_(read)(fd, &ch, 1);
592 if (n == 0) return False; /* the next call will return True */
593 if (ch == '\n') break;
594 if (i > 0 && i == nBuf-1) i--;
595 buf[i++] = ch; buf[i] = 0;
596 }
597 while (i > 1 && VG_ISSPACE(buf[i-1])) {
598 i--; buf[i] = 0;
599 };
600
601 /* VG_(printf)("The line is `%s'\n", buf); */
602 /* Ok, we have a line. If a non-comment line, return.
603 If a comment line, start all over again. */
604 if (buf[0] != '#') return False;
605 }
606}
607
608
609/* *p_caller contains the raw name of a caller, supposedly either
610 fun:some_function_name or
611 obj:some_object_name.
612 Set *p_ty accordingly and advance *p_caller over the descriptor
613 (fun: or obj:) part.
614 Returns False if failed.
615*/
njn25e49d8e72002-09-23 09:36:25 +0000616static Bool setLocationTy ( Char** p_caller, SuppLocTy* p_ty )
sewardjde4a1d02002-03-22 01:27:54 +0000617{
618 if (VG_(strncmp)(*p_caller, "fun:", 4) == 0) {
619 (*p_caller) += 4;
620 *p_ty = FunName;
621 return True;
622 }
623 if (VG_(strncmp)(*p_caller, "obj:", 4) == 0) {
624 (*p_caller) += 4;
625 *p_ty = ObjName;
626 return True;
627 }
628 VG_(printf)("location should start with fun: or obj:\n");
629 return False;
630}
631
632
njn11cc9252002-10-07 14:42:59 +0000633/* Look for "skin" in a string like "skin1,skin2,skin3" */
634static __inline__
635Bool skin_name_present(Char *name, Char *names)
636{
637 Bool found;
638 Char *s = NULL; /* Shut gcc up */
639 Int len = VG_(strlen)(name);
640
641 found = (NULL != (s = VG_(strstr)(names, name)) &&
642 (s == names || *(s-1) == ',') &&
643 (*(s+len) == ',' || *(s+len) == '\0')
644 );
645
646 return found;
647}
648
sewardjde4a1d02002-03-22 01:27:54 +0000649/* Read suppressions from the file specified in vg_clo_suppressions
650 and place them in the suppressions list. If there's any difficulty
651 doing this, just give up -- there's no point in trying to recover.
652*/
sewardjde4a1d02002-03-22 01:27:54 +0000653static void load_one_suppressions_file ( Char* filename )
654{
655# define N_BUF 200
njnc40c3a82002-10-02 11:02:27 +0000656 Int fd, i;
657 Bool eof;
658 Char buf[N_BUF+1];
njn11cc9252002-10-07 14:42:59 +0000659 Char* skin_names;
njnc40c3a82002-10-02 11:02:27 +0000660 Char* supp_name;
661
njn25e49d8e72002-09-23 09:36:25 +0000662 fd = VG_(open)( filename, VKI_O_RDONLY, 0 );
sewardjde4a1d02002-03-22 01:27:54 +0000663 if (fd == -1) {
njn25e49d8e72002-09-23 09:36:25 +0000664 VG_(message)(Vg_UserMsg, "FATAL: can't open suppressions file `%s'",
sewardjde4a1d02002-03-22 01:27:54 +0000665 filename );
666 VG_(exit)(1);
667 }
668
669 while (True) {
njn25e49d8e72002-09-23 09:36:25 +0000670 /* Assign and initialise the two suppression halves (core and skin) */
njn810086f2002-11-14 12:42:47 +0000671 Supp* supp;
672 supp = VG_(arena_malloc)(VG_AR_CORE, sizeof(Supp));
sewardjde4a1d02002-03-22 01:27:54 +0000673 supp->count = 0;
njn25e49d8e72002-09-23 09:36:25 +0000674 for (i = 0; i < VG_N_SUPP_CALLERS; i++) supp->caller[i] = NULL;
njn810086f2002-11-14 12:42:47 +0000675 supp->string = supp->extra = NULL;
sewardjde4a1d02002-03-22 01:27:54 +0000676
njn4ba5a792002-09-30 10:23:54 +0000677 eof = VG_(get_line) ( fd, buf, N_BUF );
sewardjde4a1d02002-03-22 01:27:54 +0000678 if (eof) break;
679
njn43c799e2003-04-08 00:08:52 +0000680 if (!VG_STREQ(buf, "{")) goto syntax_error;
sewardjde4a1d02002-03-22 01:27:54 +0000681
njn4ba5a792002-09-30 10:23:54 +0000682 eof = VG_(get_line) ( fd, buf, N_BUF );
njn43c799e2003-04-08 00:08:52 +0000683 if (eof || VG_STREQ(buf, "}")) goto syntax_error;
njn25e49d8e72002-09-23 09:36:25 +0000684 supp->sname = VG_(arena_strdup)(VG_AR_CORE, buf);
sewardjde4a1d02002-03-22 01:27:54 +0000685
njn4ba5a792002-09-30 10:23:54 +0000686 eof = VG_(get_line) ( fd, buf, N_BUF );
njn25e49d8e72002-09-23 09:36:25 +0000687
sewardjde4a1d02002-03-22 01:27:54 +0000688 if (eof) goto syntax_error;
sewardjde4a1d02002-03-22 01:27:54 +0000689
njn11cc9252002-10-07 14:42:59 +0000690 /* Check it has the "skin1,skin2,...:supp" form (look for ':') */
njnc40c3a82002-10-02 11:02:27 +0000691 i = 0;
692 while (True) {
693 if (buf[i] == ':') break;
694 if (buf[i] == '\0') goto syntax_error;
695 i++;
njn25e49d8e72002-09-23 09:36:25 +0000696 }
njnc40c3a82002-10-02 11:02:27 +0000697 buf[i] = '\0'; /* Replace ':', splitting into two strings */
698
njn11cc9252002-10-07 14:42:59 +0000699 skin_names = & buf[0];
700 supp_name = & buf[i+1];
njnc40c3a82002-10-02 11:02:27 +0000701
njn11cc9252002-10-07 14:42:59 +0000702 /* Is it a core suppression? */
703 if (VG_(needs).core_errors && skin_name_present("core", skin_names))
njnc40c3a82002-10-02 11:02:27 +0000704 {
njn43c799e2003-04-08 00:08:52 +0000705 if (VG_STREQ(supp_name, "PThread"))
njn810086f2002-11-14 12:42:47 +0000706 supp->skind = PThreadSupp;
njnc40c3a82002-10-02 11:02:27 +0000707 else
708 goto syntax_error;
709 }
710
njn11cc9252002-10-07 14:42:59 +0000711 /* Is it a skin suppression? */
712 else if (VG_(needs).skin_errors &&
713 skin_name_present(VG_(details).name, skin_names))
njnc40c3a82002-10-02 11:02:27 +0000714 {
njn810086f2002-11-14 12:42:47 +0000715 if (SK_(recognised_suppression)(supp_name, supp))
njnc40c3a82002-10-02 11:02:27 +0000716 {
njn810086f2002-11-14 12:42:47 +0000717 /* Do nothing, function fills in supp->skind */
njnc40c3a82002-10-02 11:02:27 +0000718 } else
719 goto syntax_error;
720 }
721
njn25e49d8e72002-09-23 09:36:25 +0000722 else {
njnc40c3a82002-10-02 11:02:27 +0000723 /* Ignore rest of suppression */
njn25e49d8e72002-09-23 09:36:25 +0000724 while (True) {
njn4ba5a792002-09-30 10:23:54 +0000725 eof = VG_(get_line) ( fd, buf, N_BUF );
njn25e49d8e72002-09-23 09:36:25 +0000726 if (eof) goto syntax_error;
njn43c799e2003-04-08 00:08:52 +0000727 if (VG_STREQ(buf, "}"))
njn25e49d8e72002-09-23 09:36:25 +0000728 break;
729 }
730 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000731 }
732
njn25e49d8e72002-09-23 09:36:25 +0000733 if (VG_(needs).skin_errors &&
njn810086f2002-11-14 12:42:47 +0000734 !SK_(read_extra_suppression_info)(fd, buf, N_BUF, supp))
sewardjde4a1d02002-03-22 01:27:54 +0000735 goto syntax_error;
736
njn25e49d8e72002-09-23 09:36:25 +0000737 /* "i > 0" ensures at least one caller read. */
njn633de322003-05-12 20:40:13 +0000738 for (i = 0; i <= VG_N_SUPP_CALLERS; i++) {
njn4ba5a792002-09-30 10:23:54 +0000739 eof = VG_(get_line) ( fd, buf, N_BUF );
sewardjde4a1d02002-03-22 01:27:54 +0000740 if (eof) goto syntax_error;
njn43c799e2003-04-08 00:08:52 +0000741 if (i > 0 && VG_STREQ(buf, "}"))
njn25e49d8e72002-09-23 09:36:25 +0000742 break;
njn633de322003-05-12 20:40:13 +0000743 if (i == VG_N_SUPP_CALLERS)
744 break;
njn25e49d8e72002-09-23 09:36:25 +0000745 supp->caller[i] = VG_(arena_strdup)(VG_AR_CORE, buf);
746 if (!setLocationTy(&(supp->caller[i]), &(supp->caller_ty[i])))
747 goto syntax_error;
sewardjde4a1d02002-03-22 01:27:54 +0000748 }
749
sewardj57a8f5f2003-07-06 01:40:11 +0000750 /* make sure to grab the '}' if the num callers is >=
751 VG_N_SUPP_CALLERS */
752 if (!VG_STREQ(buf, "}")) {
753 do {
754 eof = VG_(get_line) ( fd, buf, N_BUF );
755 } while (!eof && !VG_STREQ(buf, "}"));
756 }
757
sewardjde4a1d02002-03-22 01:27:54 +0000758 supp->next = vg_suppressions;
759 vg_suppressions = supp;
760 }
sewardjde4a1d02002-03-22 01:27:54 +0000761 VG_(close)(fd);
762 return;
763
764 syntax_error:
765 if (eof) {
766 VG_(message)(Vg_UserMsg,
767 "FATAL: in suppressions file `%s': unexpected EOF",
768 filename );
769 } else {
770 VG_(message)(Vg_UserMsg,
njn11cc9252002-10-07 14:42:59 +0000771 "FATAL: in suppressions file: `%s': syntax error on: %s",
sewardjde4a1d02002-03-22 01:27:54 +0000772 filename, buf );
773 }
774 VG_(close)(fd);
775 VG_(message)(Vg_UserMsg, "exiting now.");
776 VG_(exit)(1);
777
778# undef N_BUF
779}
780
781
782void VG_(load_suppressions) ( void )
783{
784 Int i;
785 vg_suppressions = NULL;
786 for (i = 0; i < VG_(clo_n_suppressions); i++) {
787 if (VG_(clo_verbosity) > 1) {
788 VG_(message)(Vg_UserMsg, "Reading suppressions file: %s",
789 VG_(clo_suppressions)[i] );
790 }
791 load_one_suppressions_file( VG_(clo_suppressions)[i] );
792 }
793}
794
njn25e49d8e72002-09-23 09:36:25 +0000795/* Return the name of an erring fn in a way which is useful
796 for comparing against the contents of a suppressions file.
797 Doesn't demangle the fn name, because we want to refer to
798 mangled names in the suppressions file.
sewardj99aac972002-12-26 01:53:45 +0000799*/
njn43c799e2003-04-08 00:08:52 +0000800static void get_objname_fnname ( Addr a, Char* obj_buf, Int n_obj_buf,
801 Char* fun_buf, Int n_fun_buf )
njn25e49d8e72002-09-23 09:36:25 +0000802{
803 (void)VG_(get_objname) ( a, obj_buf, n_obj_buf );
804 (void)VG_(get_fnname_nodemangle)( a, fun_buf, n_fun_buf );
805}
806
807static __inline__
njn810086f2002-11-14 12:42:47 +0000808Bool supp_matches_error(Supp* su, Error* err)
njn25e49d8e72002-09-23 09:36:25 +0000809{
njn810086f2002-11-14 12:42:47 +0000810 switch (su->skind) {
njn25e49d8e72002-09-23 09:36:25 +0000811 case PThreadSupp:
njn810086f2002-11-14 12:42:47 +0000812 return (err->ekind == PThreadErr);
njn25e49d8e72002-09-23 09:36:25 +0000813 default:
814 if (VG_(needs).skin_errors) {
njn810086f2002-11-14 12:42:47 +0000815 return SK_(error_matches_suppression)(err, su);
njn25e49d8e72002-09-23 09:36:25 +0000816 } else {
817 VG_(printf)(
818 "\nUnhandled suppression type: %u. VG_(needs).skin_errors\n"
819 "probably needs to be set.\n",
njn810086f2002-11-14 12:42:47 +0000820 err->ekind);
njne427a662002-10-02 11:08:25 +0000821 VG_(skin_panic)("unhandled suppression type");
njn25e49d8e72002-09-23 09:36:25 +0000822 }
823 }
824}
825
826static __inline__
njn810086f2002-11-14 12:42:47 +0000827Bool supp_matches_callers(Supp* su, Char caller_obj[][M_VG_ERRTXT],
828 Char caller_fun[][M_VG_ERRTXT])
njn25e49d8e72002-09-23 09:36:25 +0000829{
830 Int i;
831
njn633de322003-05-12 20:40:13 +0000832 for (i = 0; i < VG_N_SUPP_CALLERS && su->caller[i] != NULL; i++) {
njn25e49d8e72002-09-23 09:36:25 +0000833 switch (su->caller_ty[i]) {
njn4ba5a792002-09-30 10:23:54 +0000834 case ObjName: if (VG_(string_match)(su->caller[i],
835 caller_obj[i])) break;
njn25e49d8e72002-09-23 09:36:25 +0000836 return False;
njn4ba5a792002-09-30 10:23:54 +0000837 case FunName: if (VG_(string_match)(su->caller[i],
838 caller_fun[i])) break;
njn25e49d8e72002-09-23 09:36:25 +0000839 return False;
njn43c799e2003-04-08 00:08:52 +0000840 default: VG_(skin_panic)("supp_matches_callers");
njn25e49d8e72002-09-23 09:36:25 +0000841 }
842 }
843
844 /* If we reach here, it's a match */
845 return True;
846}
sewardjde4a1d02002-03-22 01:27:54 +0000847
njn810086f2002-11-14 12:42:47 +0000848/* Does an error context match a suppression? ie is this a suppressible
849 error? If so, return a pointer to the Supp record, otherwise NULL.
njn25e49d8e72002-09-23 09:36:25 +0000850 Tries to minimise the number of symbol searches since they are expensive.
sewardjde4a1d02002-03-22 01:27:54 +0000851*/
njn810086f2002-11-14 12:42:47 +0000852static Supp* is_suppressible_error ( Error* err )
sewardjde4a1d02002-03-22 01:27:54 +0000853{
njn25e49d8e72002-09-23 09:36:25 +0000854 Int i;
sewardjde4a1d02002-03-22 01:27:54 +0000855
njn25e49d8e72002-09-23 09:36:25 +0000856 Char caller_obj[VG_N_SUPP_CALLERS][M_VG_ERRTXT];
857 Char caller_fun[VG_N_SUPP_CALLERS][M_VG_ERRTXT];
sewardjde4a1d02002-03-22 01:27:54 +0000858
njn810086f2002-11-14 12:42:47 +0000859 Supp* su;
sewardjde4a1d02002-03-22 01:27:54 +0000860
njn25e49d8e72002-09-23 09:36:25 +0000861 /* get_objname_fnname() writes the function name and object name if
njn43c799e2003-04-08 00:08:52 +0000862 it finds them in the debug info. So the strings in the suppression
njn25e49d8e72002-09-23 09:36:25 +0000863 file should match these.
sewardjde4a1d02002-03-22 01:27:54 +0000864 */
865
866 /* Initialise these strs so they are always safe to compare, even
njn25e49d8e72002-09-23 09:36:25 +0000867 if get_objname_fnname doesn't write anything to them. */
868 for (i = 0; i < VG_N_SUPP_CALLERS; i++)
869 caller_obj[i][0] = caller_fun[i][0] = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000870
njn25e49d8e72002-09-23 09:36:25 +0000871 for (i = 0; i < VG_N_SUPP_CALLERS && i < VG_(clo_backtrace_size); i++) {
njn43c799e2003-04-08 00:08:52 +0000872 get_objname_fnname ( err->where->eips[i], caller_obj[i], M_VG_ERRTXT,
873 caller_fun[i], M_VG_ERRTXT );
sewardjde4a1d02002-03-22 01:27:54 +0000874 }
875
876 /* See if the error context matches any suppression. */
877 for (su = vg_suppressions; su != NULL; su = su->next) {
njn25e49d8e72002-09-23 09:36:25 +0000878 if (supp_matches_error(su, err) &&
879 supp_matches_callers(su, caller_obj, caller_fun)) {
880 return su;
sewardjde4a1d02002-03-22 01:27:54 +0000881 }
sewardjde4a1d02002-03-22 01:27:54 +0000882 }
njn25e49d8e72002-09-23 09:36:25 +0000883 return NULL; /* no matches */
sewardjde4a1d02002-03-22 01:27:54 +0000884}
885
sewardjde4a1d02002-03-22 01:27:54 +0000886/*--------------------------------------------------------------------*/
887/*--- end vg_errcontext.c ---*/
888/*--------------------------------------------------------------------*/