blob: 61753391c00971b07510998e3f5b3431e63aac5d [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
2/*--------------------------------------------------------------------*/
3/*--- Management of error messages. vg_errcontext.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
7 This file is part of Valgrind, an x86 protected-mode emulator
8 designed for debugging and profiling binaries on x86-Unixes.
9
10 Copyright (C) 2000-2002 Julian Seward
11 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
28 The GNU General Public License is contained in the file LICENSE.
29*/
30
31#include "vg_include.h"
32#include "vg_constants.h"
33
34
35/*------------------------------------------------------------*/
36/*--- Defns ---*/
37/*------------------------------------------------------------*/
38
39/* Suppression is a type describing an error which we want to
40 suppress, ie, not show the user, usually because it is caused by a
41 problem in a library which we can't fix, replace or work around.
42 Suppressions are read from a file at startup time, specified by
43 vg_clo_suppressions, and placed in the vg_suppressions list. This
44 gives flexibility so that new suppressions can be added to the file
45 as and when needed.
46*/
47typedef
48 enum {
49 /* Bad syscall params */
50 Param,
51 /* Use of invalid values of given size */
52 Value0, Value1, Value2, Value4, Value8,
53 /* Invalid read/write attempt at given size */
54 Addr1, Addr2, Addr4, Addr8,
55 /* Invalid or mismatching free */
56 FreeS
57 }
58 SuppressionKind;
59
60
61/* For each caller specified for a suppression, record the nature of
62 the caller name. */
63typedef
64 enum {
65 /* Name is of an shared object file. */
66 ObjName,
67 /* Name is of a function. */
68 FunName
69 }
70 SuppressionLocTy;
71
72
73/* A complete suppression record. */
74typedef
75 struct _Suppression {
76 struct _Suppression* next;
77 /* The number of times this error has been suppressed. */
78 Int count;
79 /* The name by which the suppression is referred to. */
80 Char* sname;
81 /* What kind of suppression. */
82 SuppressionKind skind;
83 /* Name of syscall param if skind==Param */
84 Char* param;
85 /* Name of fn where err occurs, and immediate caller (mandatory). */
86 SuppressionLocTy caller0_ty;
87 Char* caller0;
88 SuppressionLocTy caller1_ty;
89 Char* caller1;
90 /* Optional extra callers. */
91 SuppressionLocTy caller2_ty;
92 Char* caller2;
93 SuppressionLocTy caller3_ty;
94 Char* caller3;
95 }
96 Suppression;
97
98
99/* ErrContext is a type for recording just enough info to generate an
100 error report for an illegal memory access. The idea is that
101 (typically) the same few points in the program generate thousands
102 of illegal accesses, and we don't want to spew out a fresh error
103 message for each one. Instead, we use these structures to common
104 up duplicates.
105*/
106
107/* What kind of error it is. */
108typedef
109 enum { ValueErr, AddrErr,
110 ParamErr, UserErr, /* behaves like an anonymous ParamErr */
111 FreeErr, FreeMismatchErr }
112 ErrKind;
113
114/* What kind of memory access is involved in the error? */
115typedef
116 enum { ReadAxs, WriteAxs, ExecAxs }
117 AxsKind;
118
119/* Top-level struct for recording errors. */
120typedef
121 struct _ErrContext {
122 /* ALL */
123 struct _ErrContext* next;
124 /* ALL */
125 /* NULL if unsuppressed; or ptr to suppression record. */
126 Suppression* supp;
127 /* ALL */
128 Int count;
129 /* ALL */
130 ErrKind ekind;
131 /* ALL */
132 ExeContext* where;
133 /* Addr */
134 AxsKind axskind;
135 /* Addr, Value */
136 Int size;
137 /* Addr, Free, Param, User */
138 Addr addr;
139 /* Addr, Free, Param, User */
140 AddrInfo addrinfo;
141 /* Param */
142 Char* syscall_param;
143 /* Param, User */
144 Bool isWriteableLack;
sewardj1e8cdc92002-04-18 11:37:52 +0000145 /* ALL */
146 ThreadId tid;
sewardj35805422002-04-21 13:05:34 +0000147 /* ALL */
148 /* These record %EIP, %ESP and %EBP at the error point. They
149 are only used to make GDB-attaching convenient; there is no
150 other purpose; specifically they are not used to do
151 comparisons between errors. */
152 UInt m_eip;
153 UInt m_esp;
154 UInt m_ebp;
sewardjde4a1d02002-03-22 01:27:54 +0000155 }
156 ErrContext;
157
158/* The list of error contexts found, both suppressed and unsuppressed.
159 Initially empty, and grows as errors are detected. */
160static ErrContext* vg_err_contexts = NULL;
161
162/* The list of suppression directives, as read from the specified
163 suppressions file. */
164static Suppression* vg_suppressions = NULL;
165
166/* Running count of unsuppressed errors detected. */
167static UInt vg_n_errs_found = 0;
168
169/* Running count of suppressed errors detected. */
170static UInt vg_n_errs_suppressed = 0;
171
sewardjc96f9312002-04-24 20:20:22 +0000172/* Used to disable further error reporting once some huge number of
173 errors have already been logged. */
174static Bool vg_ignore_errors = False;
175
sewardjde4a1d02002-03-22 01:27:54 +0000176/* forwards ... */
177static Suppression* is_suppressible_error ( ErrContext* ec );
178
179
180/*------------------------------------------------------------*/
181/*--- Helper fns ---*/
182/*------------------------------------------------------------*/
183
184
185static void clear_AddrInfo ( AddrInfo* ai )
186{
187 ai->akind = Unknown;
188 ai->blksize = 0;
189 ai->rwoffset = 0;
190 ai->lastchange = NULL;
sewardj1e8cdc92002-04-18 11:37:52 +0000191 ai->stack_tid = VG_INVALID_THREADID;
sewardjb581a132002-05-08 00:32:50 +0000192 ai->maybe_gcc = False;
sewardjde4a1d02002-03-22 01:27:54 +0000193}
194
195static void clear_ErrContext ( ErrContext* ec )
196{
197 ec->next = NULL;
198 ec->supp = NULL;
199 ec->count = 0;
200 ec->ekind = ValueErr;
201 ec->where = NULL;
202 ec->axskind = ReadAxs;
203 ec->size = 0;
204 ec->addr = 0;
205 clear_AddrInfo ( &ec->addrinfo );
206 ec->syscall_param = NULL;
207 ec->isWriteableLack = False;
sewardj35805422002-04-21 13:05:34 +0000208 ec->m_eip = 0xDEADB00F;
209 ec->m_esp = 0xDEADBE0F;
210 ec->m_ebp = 0xDEADB0EF;
sewardj1e8cdc92002-04-18 11:37:52 +0000211 ec->tid = VG_INVALID_THREADID;
sewardjde4a1d02002-03-22 01:27:54 +0000212}
213
214
215static __inline__
216Bool vg_eq_ExeContext ( Bool top_2_only,
217 ExeContext* e1, ExeContext* e2 )
218{
219 /* Note that frames after the 4th are always ignored. */
220 if (top_2_only) {
221 return VG_(eq_ExeContext_top2(e1, e2));
222 } else {
223 return VG_(eq_ExeContext_top4(e1, e2));
224 }
225}
226
227
228static Bool eq_AddrInfo ( Bool cheap_addr_cmp,
229 AddrInfo* ai1, AddrInfo* ai2 )
230{
sewardjb581a132002-05-08 00:32:50 +0000231 if (ai1->akind != Undescribed
232 && ai2->akind != Undescribed
233 && ai1->akind != ai2->akind)
sewardjde4a1d02002-03-22 01:27:54 +0000234 return False;
235 if (ai1->akind == Freed || ai1->akind == Mallocd) {
236 if (ai1->blksize != ai2->blksize)
237 return False;
238 if (!vg_eq_ExeContext(cheap_addr_cmp,
239 ai1->lastchange, ai2->lastchange))
240 return False;
241 }
242 return True;
243}
244
245/* Compare error contexts, to detect duplicates. Note that if they
246 are otherwise the same, the faulting addrs and associated rwoffsets
247 are allowed to be different. */
248
249static Bool eq_ErrContext ( Bool cheap_addr_cmp,
250 ErrContext* e1, ErrContext* e2 )
251{
252 if (e1->ekind != e2->ekind)
253 return False;
254 if (!vg_eq_ExeContext(cheap_addr_cmp, e1->where, e2->where))
255 return False;
256
257 switch (e1->ekind) {
258 case UserErr:
259 case ParamErr:
260 if (e1->isWriteableLack != e2->isWriteableLack) return False;
261 if (e1->ekind == ParamErr
262 && 0 != VG_(strcmp)(e1->syscall_param, e2->syscall_param))
263 return False;
264 return True;
265 case FreeErr:
266 case FreeMismatchErr:
267 if (e1->addr != e2->addr) return False;
268 if (!eq_AddrInfo(cheap_addr_cmp, &e1->addrinfo, &e2->addrinfo))
269 return False;
270 return True;
271 case AddrErr:
272 if (e1->axskind != e2->axskind) return False;
273 if (e1->size != e2->size) return False;
274 if (!eq_AddrInfo(cheap_addr_cmp, &e1->addrinfo, &e2->addrinfo))
275 return False;
276 return True;
277 case ValueErr:
278 if (e1->size != e2->size) return False;
279 return True;
280 default:
281 VG_(panic)("eq_ErrContext");
282 }
283}
284
285static void pp_AddrInfo ( Addr a, AddrInfo* ai )
286{
287 switch (ai->akind) {
288 case Stack:
sewardj1e8cdc92002-04-18 11:37:52 +0000289 VG_(message)(Vg_UserMsg,
290 " Address 0x%x is on thread %d's stack",
sewardjb48e5002002-05-13 00:16:03 +0000291 a, ai->stack_tid);
sewardjde4a1d02002-03-22 01:27:54 +0000292 break;
293 case Unknown:
sewardjb581a132002-05-08 00:32:50 +0000294 if (ai->maybe_gcc) {
295 VG_(message)(Vg_UserMsg,
296 " Address 0x%x is just below %%esp. Possibly a bug in GCC/G++",
297 a);
298 VG_(message)(Vg_UserMsg,
299 " v 2.96 or 3.0.X. To suppress, use: --workaround-gcc296-bugs=yes");
300 } else {
301 VG_(message)(Vg_UserMsg,
302 " Address 0x%x is not stack'd, malloc'd or free'd", a);
303 }
sewardjde4a1d02002-03-22 01:27:54 +0000304 break;
305 case Freed: case Mallocd: case UserG: case UserS: {
306 UInt delta;
307 UChar* relative;
308 if (ai->rwoffset < 0) {
309 delta = (UInt)(- ai->rwoffset);
310 relative = "before";
311 } else if (ai->rwoffset >= ai->blksize) {
312 delta = ai->rwoffset - ai->blksize;
313 relative = "after";
314 } else {
315 delta = ai->rwoffset;
316 relative = "inside";
317 }
318 if (ai->akind == UserS) {
319 VG_(message)(Vg_UserMsg,
320 " Address 0x%x is %d bytes %s a %d-byte stack red-zone created",
321 a, delta, relative,
322 ai->blksize );
323 } else {
324 VG_(message)(Vg_UserMsg,
325 " Address 0x%x is %d bytes %s a block of size %d %s",
326 a, delta, relative,
327 ai->blksize,
328 ai->akind==Mallocd ? "alloc'd"
329 : ai->akind==Freed ? "free'd"
330 : "client-defined");
331 }
332 VG_(pp_ExeContext)(ai->lastchange);
333 break;
334 }
335 default:
336 VG_(panic)("pp_AddrInfo");
337 }
338}
339
340static void pp_ErrContext ( ErrContext* ec, Bool printCount )
341{
342 if (printCount)
343 VG_(message)(Vg_UserMsg, "Observed %d times:", ec->count );
sewardj6072c362002-04-19 14:40:57 +0000344 if (ec->tid > 1)
sewardj1e8cdc92002-04-18 11:37:52 +0000345 VG_(message)(Vg_UserMsg, "Thread %d:", ec->tid );
sewardjde4a1d02002-03-22 01:27:54 +0000346 switch (ec->ekind) {
347 case ValueErr:
348 if (ec->size == 0) {
sewardja7dc7952002-03-24 11:29:13 +0000349 VG_(message)(
350 Vg_UserMsg,
351 "Conditional jump or move depends on uninitialised value(s)");
sewardjde4a1d02002-03-22 01:27:54 +0000352 } else {
353 VG_(message)(Vg_UserMsg,
354 "Use of uninitialised value of size %d",
355 ec->size);
356 }
357 VG_(pp_ExeContext)(ec->where);
358 break;
359 case AddrErr:
360 switch (ec->axskind) {
361 case ReadAxs:
362 VG_(message)(Vg_UserMsg, "Invalid read of size %d",
363 ec->size );
364 break;
365 case WriteAxs:
366 VG_(message)(Vg_UserMsg, "Invalid write of size %d",
367 ec->size );
368 break;
369 case ExecAxs:
370 VG_(message)(Vg_UserMsg, "Jump to the invalid address "
371 "stated on the next line");
372 break;
373 default:
374 VG_(panic)("pp_ErrContext(axskind)");
375 }
376 VG_(pp_ExeContext)(ec->where);
377 pp_AddrInfo(ec->addr, &ec->addrinfo);
378 break;
379 case FreeErr:
380 VG_(message)(Vg_UserMsg,"Invalid free() / delete / delete[]");
381 /* fall through */
382 case FreeMismatchErr:
383 if (ec->ekind == FreeMismatchErr)
384 VG_(message)(Vg_UserMsg,
385 "Mismatched free() / delete / delete []");
386 VG_(pp_ExeContext)(ec->where);
387 pp_AddrInfo(ec->addr, &ec->addrinfo);
388 break;
389 case ParamErr:
390 if (ec->isWriteableLack) {
391 VG_(message)(Vg_UserMsg,
392 "Syscall param %s contains unaddressable byte(s)",
393 ec->syscall_param );
394 } else {
395 VG_(message)(Vg_UserMsg,
396 "Syscall param %s contains uninitialised or "
397 "unaddressable byte(s)",
398 ec->syscall_param);
399 }
400 VG_(pp_ExeContext)(ec->where);
401 pp_AddrInfo(ec->addr, &ec->addrinfo);
402 break;
403 case UserErr:
404 if (ec->isWriteableLack) {
405 VG_(message)(Vg_UserMsg,
406 "Unaddressable byte(s) found during client check request");
407 } else {
408 VG_(message)(Vg_UserMsg,
409 "Uninitialised or "
410 "unaddressable byte(s) found during client check request");
411 }
412 VG_(pp_ExeContext)(ec->where);
413 pp_AddrInfo(ec->addr, &ec->addrinfo);
414 break;
415 default:
416 VG_(panic)("pp_ErrContext");
417 }
418}
419
420
421/* Figure out if we want to attach for GDB for this error, possibly
422 by asking the user. */
423static
424Bool vg_is_GDB_attach_requested ( void )
425{
426 Char ch, ch2;
427 Int res;
428
429 if (VG_(clo_GDB_attach) == False)
430 return False;
431
432 VG_(message)(Vg_UserMsg, "");
433
434 again:
435 VG_(printf)(
436 "==%d== "
437 "---- Attach to GDB ? --- [Return/N/n/Y/y/C/c] ---- ",
438 VG_(getpid)()
439 );
440
441 res = VG_(read)(0 /*stdin*/, &ch, 1);
442 if (res != 1) goto ioerror;
443 /* res == 1 */
444 if (ch == '\n') return False;
445 if (ch != 'N' && ch != 'n' && ch != 'Y' && ch != 'y'
446 && ch != 'C' && ch != 'c') goto again;
447
448 res = VG_(read)(0 /*stdin*/, &ch2, 1);
449 if (res != 1) goto ioerror;
450 if (ch2 != '\n') goto again;
451
452 /* No, don't want to attach. */
453 if (ch == 'n' || ch == 'N') return False;
454 /* Yes, want to attach. */
455 if (ch == 'y' || ch == 'Y') return True;
456 /* No, don't want to attach, and don't ask again either. */
457 vg_assert(ch == 'c' || ch == 'C');
458
459 ioerror:
460 VG_(clo_GDB_attach) = False;
461 return False;
462}
463
464
465/* Top-level entry point to the error management subsystem. All
466 detected errors are notified here; this routine decides if/when the
467 user should see the error. */
468static void VG_(maybe_add_context) ( ErrContext* ec )
469{
470 ErrContext* p;
471 ErrContext* p_prev;
472 Bool cheap_addr_cmp = False;
473 static Bool is_first_shown_context = True;
474 static Bool stopping_message = False;
475 static Bool slowdown_message = False;
476 static Int vg_n_errs_shown = 0;
477
sewardj1e8cdc92002-04-18 11:37:52 +0000478 vg_assert(ec->tid >= 0 && ec->tid < VG_N_THREADS);
479
sewardjf2537be2002-04-24 21:03:47 +0000480 /* After M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN different errors have
481 been found, or M_VG_COLLECT_NO_ERRORS_AFTER_FOUND total errors
482 have been found, just refuse to collect any more. This stops
483 the burden of the error-management system becoming excessive in
484 extremely buggy programs, although it does make it pretty
485 pointless to continue the Valgrind run after this point. */
486 if (vg_n_errs_shown >= M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN
487 || vg_n_errs_found >= M_VG_COLLECT_NO_ERRORS_AFTER_FOUND) {
sewardjde4a1d02002-03-22 01:27:54 +0000488 if (!stopping_message) {
489 VG_(message)(Vg_UserMsg, "");
sewardjf2537be2002-04-24 21:03:47 +0000490
491 if (vg_n_errs_shown >= M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN) {
492 VG_(message)(Vg_UserMsg,
493 "More than %d different errors detected. "
494 "I'm not reporting any more.",
495 M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN );
496 } else {
497 VG_(message)(Vg_UserMsg,
498 "More than %d total errors detected. "
499 "I'm not reporting any more.",
500 M_VG_COLLECT_NO_ERRORS_AFTER_FOUND );
501 }
502
sewardjde4a1d02002-03-22 01:27:54 +0000503 VG_(message)(Vg_UserMsg,
sewardjf2537be2002-04-24 21:03:47 +0000504 "Final error counts will be inaccurate. Go fix your program!");
sewardjde4a1d02002-03-22 01:27:54 +0000505 VG_(message)(Vg_UserMsg, "");
506 stopping_message = True;
sewardjc96f9312002-04-24 20:20:22 +0000507 vg_ignore_errors = True;
sewardjde4a1d02002-03-22 01:27:54 +0000508 }
509 return;
510 }
511
512 /* After M_VG_COLLECT_ERRORS_SLOWLY_AFTER different errors have
513 been found, be much more conservative about collecting new
514 ones. */
515 if (vg_n_errs_shown >= M_VG_COLLECT_ERRORS_SLOWLY_AFTER) {
516 cheap_addr_cmp = True;
517 if (!slowdown_message) {
518 VG_(message)(Vg_UserMsg, "");
519 VG_(message)(Vg_UserMsg,
520 "More than %d errors detected. Subsequent errors",
521 M_VG_COLLECT_ERRORS_SLOWLY_AFTER);
522 VG_(message)(Vg_UserMsg,
523 "will still be recorded, but in less detail than before.");
524 slowdown_message = True;
525 }
526 }
527
528
529 /* First, see if we've got an error record matching this one. */
530 p = vg_err_contexts;
531 p_prev = NULL;
532 while (p != NULL) {
533 if (eq_ErrContext(cheap_addr_cmp, p, ec)) {
534 /* Found it. */
535 p->count++;
536 if (p->supp != NULL) {
537 /* Deal correctly with suppressed errors. */
538 p->supp->count++;
539 vg_n_errs_suppressed++;
540 } else {
541 vg_n_errs_found++;
542 }
543
544 /* Move p to the front of the list so that future searches
545 for it are faster. */
546 if (p_prev != NULL) {
547 vg_assert(p_prev->next == p);
548 p_prev->next = p->next;
549 p->next = vg_err_contexts;
550 vg_err_contexts = p;
551 }
552 return;
553 }
554 p_prev = p;
555 p = p->next;
556 }
557
558 /* Didn't see it. Copy and add. */
559
sewardjb581a132002-05-08 00:32:50 +0000560 /* OK, we're really going to collect it. First, describe any addr
561 info in the error. */
562 if (ec->addrinfo.akind == Undescribed)
563 VG_(describe_addr) ( ec->addr, &ec->addrinfo );
sewardjde4a1d02002-03-22 01:27:54 +0000564
565 p = VG_(malloc)(VG_AR_ERRCTXT, sizeof(ErrContext));
566 *p = *ec;
567 p->next = vg_err_contexts;
568 p->supp = is_suppressible_error(ec);
569 vg_err_contexts = p;
570 if (p->supp == NULL) {
571 vg_n_errs_found++;
572 if (!is_first_shown_context)
573 VG_(message)(Vg_UserMsg, "");
574 pp_ErrContext(p, False);
575 is_first_shown_context = False;
576 vg_n_errs_shown++;
577 /* Perhaps we want a GDB attach at this point? */
578 if (vg_is_GDB_attach_requested()) {
sewardj35805422002-04-21 13:05:34 +0000579 VG_(swizzle_esp_then_start_GDB)(
580 ec->m_eip, ec->m_esp, ec->m_ebp);
sewardjde4a1d02002-03-22 01:27:54 +0000581 }
582 } else {
583 vg_n_errs_suppressed++;
584 p->supp->count++;
585 }
586}
587
588
589
590
591/*------------------------------------------------------------*/
592/*--- Exported fns ---*/
593/*------------------------------------------------------------*/
594
sewardjaabd5ad2002-04-19 15:43:37 +0000595/* These two are called from generated code, so that the %EIP/%EBP
sewardj8c824512002-04-14 04:16:48 +0000596 values that we need in order to create proper error messages are
597 picked up out of VG_(baseBlock) rather than from the thread table
598 (vg_threads in vg_scheduler.c). */
599
sewardjde4a1d02002-03-22 01:27:54 +0000600void VG_(record_value_error) ( Int size )
601{
602 ErrContext ec;
sewardjc96f9312002-04-24 20:20:22 +0000603 if (vg_ignore_errors) return;
sewardjde4a1d02002-03-22 01:27:54 +0000604 clear_ErrContext( &ec );
605 ec.count = 1;
606 ec.next = NULL;
sewardj8c824512002-04-14 04:16:48 +0000607 ec.where = VG_(get_ExeContext)( False, VG_(baseBlock)[VGOFF_(m_eip)],
608 VG_(baseBlock)[VGOFF_(m_ebp)] );
sewardjde4a1d02002-03-22 01:27:54 +0000609 ec.ekind = ValueErr;
610 ec.size = size;
sewardj1e8cdc92002-04-18 11:37:52 +0000611 ec.tid = VG_(get_current_tid)();
sewardj35805422002-04-21 13:05:34 +0000612 ec.m_eip = VG_(baseBlock)[VGOFF_(m_eip)];
613 ec.m_esp = VG_(baseBlock)[VGOFF_(m_esp)];
614 ec.m_ebp = VG_(baseBlock)[VGOFF_(m_ebp)];
sewardjde4a1d02002-03-22 01:27:54 +0000615 VG_(maybe_add_context) ( &ec );
616}
617
618void VG_(record_address_error) ( Addr a, Int size, Bool isWrite )
619{
620 ErrContext ec;
sewardjb581a132002-05-08 00:32:50 +0000621 Bool just_below_esp;
sewardjc96f9312002-04-24 20:20:22 +0000622 if (vg_ignore_errors) return;
sewardjde4a1d02002-03-22 01:27:54 +0000623
sewardjb581a132002-05-08 00:32:50 +0000624 just_below_esp
625 = VG_(is_just_below_ESP)( VG_(baseBlock)[VGOFF_(m_esp)], a );
626
sewardjde4a1d02002-03-22 01:27:54 +0000627 /* If this is caused by an access immediately below %ESP, and the
628 user asks nicely, we just ignore it. */
sewardjb581a132002-05-08 00:32:50 +0000629 if (VG_(clo_workaround_gcc296_bugs) && just_below_esp)
sewardjde4a1d02002-03-22 01:27:54 +0000630 return;
631
632 clear_ErrContext( &ec );
633 ec.count = 1;
634 ec.next = NULL;
sewardj8c824512002-04-14 04:16:48 +0000635 ec.where = VG_(get_ExeContext)( False, VG_(baseBlock)[VGOFF_(m_eip)],
636 VG_(baseBlock)[VGOFF_(m_ebp)] );
sewardjde4a1d02002-03-22 01:27:54 +0000637 ec.ekind = AddrErr;
638 ec.axskind = isWrite ? WriteAxs : ReadAxs;
639 ec.size = size;
640 ec.addr = a;
sewardj1e8cdc92002-04-18 11:37:52 +0000641 ec.tid = VG_(get_current_tid)();
sewardj35805422002-04-21 13:05:34 +0000642 ec.m_eip = VG_(baseBlock)[VGOFF_(m_eip)];
643 ec.m_esp = VG_(baseBlock)[VGOFF_(m_esp)];
644 ec.m_ebp = VG_(baseBlock)[VGOFF_(m_ebp)];
sewardjb581a132002-05-08 00:32:50 +0000645 ec.addrinfo.akind = Undescribed;
646 ec.addrinfo.maybe_gcc = just_below_esp;
sewardjde4a1d02002-03-22 01:27:54 +0000647 VG_(maybe_add_context) ( &ec );
648}
649
sewardjde4a1d02002-03-22 01:27:54 +0000650
sewardjaabd5ad2002-04-19 15:43:37 +0000651/* These five are called not from generated code but in response to
sewardj8c824512002-04-14 04:16:48 +0000652 requests passed back to the scheduler. So we pick up %EIP/%EBP
653 values from the stored thread state, not from VG_(baseBlock). */
654
sewardjaabd5ad2002-04-19 15:43:37 +0000655void VG_(record_free_error) ( ThreadState* tst, Addr a )
656{
657 ErrContext ec;
sewardjc96f9312002-04-24 20:20:22 +0000658 if (vg_ignore_errors) return;
sewardjaabd5ad2002-04-19 15:43:37 +0000659 clear_ErrContext( &ec );
660 ec.count = 1;
661 ec.next = NULL;
sewardj7c062c92002-05-01 21:46:38 +0000662 ec.where = VG_(get_ExeContext)( False, tst->m_eip, tst->m_ebp );
sewardjaabd5ad2002-04-19 15:43:37 +0000663 ec.ekind = FreeErr;
664 ec.addr = a;
665 ec.tid = tst->tid;
sewardj35805422002-04-21 13:05:34 +0000666 ec.m_eip = tst->m_eip;
667 ec.m_esp = tst->m_esp;
668 ec.m_ebp = tst->m_ebp;
sewardjb581a132002-05-08 00:32:50 +0000669 ec.addrinfo.akind = Undescribed;
sewardjaabd5ad2002-04-19 15:43:37 +0000670 VG_(maybe_add_context) ( &ec );
671}
672
673void VG_(record_freemismatch_error) ( ThreadState* tst, Addr a )
674{
675 ErrContext ec;
sewardjc96f9312002-04-24 20:20:22 +0000676 if (vg_ignore_errors) return;
sewardjaabd5ad2002-04-19 15:43:37 +0000677 clear_ErrContext( &ec );
678 ec.count = 1;
679 ec.next = NULL;
sewardj7c062c92002-05-01 21:46:38 +0000680 ec.where = VG_(get_ExeContext)( False, tst->m_eip, tst->m_ebp );
sewardjaabd5ad2002-04-19 15:43:37 +0000681 ec.ekind = FreeMismatchErr;
682 ec.addr = a;
683 ec.tid = tst->tid;
sewardj35805422002-04-21 13:05:34 +0000684 ec.m_eip = tst->m_eip;
685 ec.m_esp = tst->m_esp;
686 ec.m_ebp = tst->m_ebp;
sewardjb581a132002-05-08 00:32:50 +0000687 ec.addrinfo.akind = Undescribed;
sewardjaabd5ad2002-04-19 15:43:37 +0000688 VG_(maybe_add_context) ( &ec );
689}
690
sewardj1e8cdc92002-04-18 11:37:52 +0000691void VG_(record_jump_error) ( ThreadState* tst, Addr a )
692{
693 ErrContext ec;
sewardjc96f9312002-04-24 20:20:22 +0000694 if (vg_ignore_errors) return;
sewardj1e8cdc92002-04-18 11:37:52 +0000695 clear_ErrContext( &ec );
696 ec.count = 1;
697 ec.next = NULL;
698 ec.where = VG_(get_ExeContext)( False, tst->m_eip, tst->m_ebp );
699 ec.ekind = AddrErr;
700 ec.axskind = ExecAxs;
701 ec.addr = a;
702 ec.tid = tst->tid;
sewardj35805422002-04-21 13:05:34 +0000703 ec.m_eip = tst->m_eip;
704 ec.m_esp = tst->m_esp;
705 ec.m_ebp = tst->m_ebp;
sewardjb581a132002-05-08 00:32:50 +0000706 ec.addrinfo.akind = Undescribed;
sewardj1e8cdc92002-04-18 11:37:52 +0000707 VG_(maybe_add_context) ( &ec );
708}
709
sewardj8c824512002-04-14 04:16:48 +0000710void VG_(record_param_err) ( ThreadState* tst, Addr a, Bool isWriteLack,
711 Char* msg )
sewardjde4a1d02002-03-22 01:27:54 +0000712{
713 ErrContext ec;
sewardjc96f9312002-04-24 20:20:22 +0000714 if (vg_ignore_errors) return;
sewardjde4a1d02002-03-22 01:27:54 +0000715 clear_ErrContext( &ec );
716 ec.count = 1;
717 ec.next = NULL;
sewardj8c824512002-04-14 04:16:48 +0000718 ec.where = VG_(get_ExeContext)( False, tst->m_eip, tst->m_ebp );
sewardjde4a1d02002-03-22 01:27:54 +0000719 ec.ekind = ParamErr;
720 ec.addr = a;
sewardj1e8cdc92002-04-18 11:37:52 +0000721 ec.tid = tst->tid;
sewardj35805422002-04-21 13:05:34 +0000722 ec.m_eip = tst->m_eip;
723 ec.m_esp = tst->m_esp;
724 ec.m_ebp = tst->m_ebp;
sewardjb581a132002-05-08 00:32:50 +0000725 ec.addrinfo.akind = Undescribed;
sewardjde4a1d02002-03-22 01:27:54 +0000726 ec.syscall_param = msg;
727 ec.isWriteableLack = isWriteLack;
728 VG_(maybe_add_context) ( &ec );
729}
730
sewardj8c824512002-04-14 04:16:48 +0000731void VG_(record_user_err) ( ThreadState* tst, Addr a, Bool isWriteLack )
sewardjde4a1d02002-03-22 01:27:54 +0000732{
733 ErrContext ec;
sewardjc96f9312002-04-24 20:20:22 +0000734 if (vg_ignore_errors) return;
sewardjde4a1d02002-03-22 01:27:54 +0000735 clear_ErrContext( &ec );
736 ec.count = 1;
737 ec.next = NULL;
sewardj8c824512002-04-14 04:16:48 +0000738 ec.where = VG_(get_ExeContext)( False, tst->m_eip, tst->m_ebp );
sewardjde4a1d02002-03-22 01:27:54 +0000739 ec.ekind = UserErr;
740 ec.addr = a;
sewardj1e8cdc92002-04-18 11:37:52 +0000741 ec.tid = tst->tid;
sewardj35805422002-04-21 13:05:34 +0000742 ec.m_eip = tst->m_eip;
743 ec.m_esp = tst->m_esp;
744 ec.m_ebp = tst->m_ebp;
sewardjb581a132002-05-08 00:32:50 +0000745 ec.addrinfo.akind = Undescribed;
sewardjde4a1d02002-03-22 01:27:54 +0000746 ec.isWriteableLack = isWriteLack;
747 VG_(maybe_add_context) ( &ec );
748}
749
750
sewardj8c824512002-04-14 04:16:48 +0000751/*------------------------------*/
752
sewardjde4a1d02002-03-22 01:27:54 +0000753void VG_(show_all_errors) ( void )
754{
755 Int i, n_min;
756 Int n_err_contexts, n_supp_contexts;
757 ErrContext *p, *p_min;
758 Suppression *su;
759 Bool any_supp;
760
761 if (VG_(clo_verbosity) == 0)
762 return;
763
764 n_err_contexts = 0;
765 for (p = vg_err_contexts; p != NULL; p = p->next) {
766 if (p->supp == NULL)
767 n_err_contexts++;
768 }
769
770 n_supp_contexts = 0;
771 for (su = vg_suppressions; su != NULL; su = su->next) {
772 if (su->count > 0)
773 n_supp_contexts++;
774 }
775
776 VG_(message)(Vg_UserMsg,
777 "ERROR SUMMARY: "
778 "%d errors from %d contexts (suppressed: %d from %d)",
779 vg_n_errs_found, n_err_contexts,
780 vg_n_errs_suppressed, n_supp_contexts );
781
782 if (VG_(clo_verbosity) <= 1)
783 return;
784
785 /* Print the contexts in order of increasing error count. */
786 for (i = 0; i < n_err_contexts; i++) {
787 n_min = (1 << 30) - 1;
788 p_min = NULL;
789 for (p = vg_err_contexts; p != NULL; p = p->next) {
790 if (p->supp != NULL) continue;
791 if (p->count < n_min) {
792 n_min = p->count;
793 p_min = p;
794 }
795 }
796 if (p_min == NULL) VG_(panic)("pp_AllErrContexts");
797
798 VG_(message)(Vg_UserMsg, "");
799 VG_(message)(Vg_UserMsg, "%d errors in context %d of %d:",
800 p_min->count,
801 i+1, n_err_contexts);
802 pp_ErrContext( p_min, False );
803
804 if ((i+1 == VG_(clo_dump_error))) {
sewardj1e8cdc92002-04-18 11:37:52 +0000805 VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to below NULLs */,
806 p_min->where->eips[0], NULL, NULL, NULL );
sewardjde4a1d02002-03-22 01:27:54 +0000807 }
808
809 p_min->count = 1 << 30;
810 }
811
812 if (n_supp_contexts > 0)
813 VG_(message)(Vg_DebugMsg, "");
814 any_supp = False;
815 for (su = vg_suppressions; su != NULL; su = su->next) {
816 if (su->count > 0) {
817 any_supp = True;
818 VG_(message)(Vg_DebugMsg, "supp: %4d %s", su->count,
819 su->sname);
820 }
821 }
822
823 if (n_err_contexts > 0) {
824 if (any_supp)
825 VG_(message)(Vg_UserMsg, "");
826 VG_(message)(Vg_UserMsg,
827 "IN SUMMARY: "
828 "%d errors from %d contexts (suppressed: %d from %d)",
829 vg_n_errs_found, n_err_contexts,
830 vg_n_errs_suppressed,
831 n_supp_contexts );
832 VG_(message)(Vg_UserMsg, "");
833 }
834}
835
836/*------------------------------------------------------------*/
837/*--- Standard suppressions ---*/
838/*------------------------------------------------------------*/
839
840/* Get a non-blank, non-comment line of at most nBuf chars from fd.
841 Skips leading spaces on the line. Return True if EOF was hit instead.
842*/
843
844#define VG_ISSPACE(ch) (((ch)==' ') || ((ch)=='\n') || ((ch)=='\t'))
845
846static Bool getLine ( Int fd, Char* buf, Int nBuf )
847{
848 Char ch;
849 Int n, i;
850 while (True) {
851 /* First, read until a non-blank char appears. */
852 while (True) {
853 n = VG_(read)(fd, &ch, 1);
854 if (n == 1 && !VG_ISSPACE(ch)) break;
855 if (n == 0) return True;
856 }
857
858 /* Now, read the line into buf. */
859 i = 0;
860 buf[i++] = ch; buf[i] = 0;
861 while (True) {
862 n = VG_(read)(fd, &ch, 1);
863 if (n == 0) return False; /* the next call will return True */
864 if (ch == '\n') break;
865 if (i > 0 && i == nBuf-1) i--;
866 buf[i++] = ch; buf[i] = 0;
867 }
868 while (i > 1 && VG_ISSPACE(buf[i-1])) {
869 i--; buf[i] = 0;
870 };
871
872 /* VG_(printf)("The line is `%s'\n", buf); */
873 /* Ok, we have a line. If a non-comment line, return.
874 If a comment line, start all over again. */
875 if (buf[0] != '#') return False;
876 }
877}
878
879
880/* *p_caller contains the raw name of a caller, supposedly either
881 fun:some_function_name or
882 obj:some_object_name.
883 Set *p_ty accordingly and advance *p_caller over the descriptor
884 (fun: or obj:) part.
885 Returns False if failed.
886*/
887static Bool setLocationTy ( Char** p_caller, SuppressionLocTy* p_ty )
888{
889 if (VG_(strncmp)(*p_caller, "fun:", 4) == 0) {
890 (*p_caller) += 4;
891 *p_ty = FunName;
892 return True;
893 }
894 if (VG_(strncmp)(*p_caller, "obj:", 4) == 0) {
895 (*p_caller) += 4;
896 *p_ty = ObjName;
897 return True;
898 }
899 VG_(printf)("location should start with fun: or obj:\n");
900 return False;
901}
902
903
904/* Read suppressions from the file specified in vg_clo_suppressions
905 and place them in the suppressions list. If there's any difficulty
906 doing this, just give up -- there's no point in trying to recover.
907*/
908#define STREQ(s1,s2) (s1 != NULL && s2 != NULL \
909 && VG_(strcmp)((s1),(s2))==0)
910
911static Char* copyStr ( Char* str )
912{
913 Int n, i;
914 Char* str2;
915 n = VG_(strlen)(str);
916 str2 = VG_(malloc)(VG_AR_PRIVATE, n+1);
917 vg_assert(n > 0);
918 for (i = 0; i < n+1; i++) str2[i] = str[i];
919 return str2;
920}
921
922static void load_one_suppressions_file ( Char* filename )
923{
924# define N_BUF 200
925 Int fd;
926 Bool eof;
927 Char buf[N_BUF+1];
928 fd = VG_(open_read)( filename );
929 if (fd == -1) {
930 VG_(message)(Vg_UserMsg,
931 "FATAL: can't open suppressions file `%s'",
932 filename );
933 VG_(exit)(1);
934 }
935
936 while (True) {
937 Suppression* supp;
938 supp = VG_(malloc)(VG_AR_PRIVATE, sizeof(Suppression));
939 supp->count = 0;
940 supp->param = supp->caller0 = supp->caller1
941 = supp->caller2 = supp->caller3 = NULL;
942
943 eof = getLine ( fd, buf, N_BUF );
944 if (eof) break;
945
946 if (!STREQ(buf, "{")) goto syntax_error;
947
948 eof = getLine ( fd, buf, N_BUF );
949 if (eof || STREQ(buf, "}")) goto syntax_error;
950 supp->sname = copyStr(buf);
951
952 eof = getLine ( fd, buf, N_BUF );
953 if (eof) goto syntax_error;
954 else if (STREQ(buf, "Param")) supp->skind = Param;
sewardja7dc7952002-03-24 11:29:13 +0000955 else if (STREQ(buf, "Value0")) supp->skind = Value0; /* backwards compat */
956 else if (STREQ(buf, "Cond")) supp->skind = Value0;
sewardjde4a1d02002-03-22 01:27:54 +0000957 else if (STREQ(buf, "Value1")) supp->skind = Value1;
958 else if (STREQ(buf, "Value2")) supp->skind = Value2;
959 else if (STREQ(buf, "Value4")) supp->skind = Value4;
960 else if (STREQ(buf, "Value8")) supp->skind = Value8;
961 else if (STREQ(buf, "Addr1")) supp->skind = Addr1;
962 else if (STREQ(buf, "Addr2")) supp->skind = Addr2;
963 else if (STREQ(buf, "Addr4")) supp->skind = Addr4;
964 else if (STREQ(buf, "Addr8")) supp->skind = Addr8;
965 else if (STREQ(buf, "Free")) supp->skind = FreeS;
966 else goto syntax_error;
967
968 if (supp->skind == Param) {
969 eof = getLine ( fd, buf, N_BUF );
970 if (eof) goto syntax_error;
971 supp->param = copyStr(buf);
972 }
973
974 eof = getLine ( fd, buf, N_BUF );
975 if (eof) goto syntax_error;
976 supp->caller0 = copyStr(buf);
977 if (!setLocationTy(&(supp->caller0), &(supp->caller0_ty)))
978 goto syntax_error;
979
980 eof = getLine ( fd, buf, N_BUF );
981 if (eof) goto syntax_error;
sewardjde4a1d02002-03-22 01:27:54 +0000982 if (!STREQ(buf, "}")) {
sewardj0873c942002-03-24 09:45:26 +0000983 supp->caller1 = copyStr(buf);
984 if (!setLocationTy(&(supp->caller1), &(supp->caller1_ty)))
sewardjde4a1d02002-03-22 01:27:54 +0000985 goto syntax_error;
sewardj0873c942002-03-24 09:45:26 +0000986
sewardjde4a1d02002-03-22 01:27:54 +0000987 eof = getLine ( fd, buf, N_BUF );
988 if (eof) goto syntax_error;
989 if (!STREQ(buf, "}")) {
sewardj0873c942002-03-24 09:45:26 +0000990 supp->caller2 = copyStr(buf);
991 if (!setLocationTy(&(supp->caller2), &(supp->caller2_ty)))
sewardjde4a1d02002-03-22 01:27:54 +0000992 goto syntax_error;
sewardj0873c942002-03-24 09:45:26 +0000993
sewardjde4a1d02002-03-22 01:27:54 +0000994 eof = getLine ( fd, buf, N_BUF );
sewardj0873c942002-03-24 09:45:26 +0000995 if (eof) goto syntax_error;
996 if (!STREQ(buf, "}")) {
997 supp->caller3 = copyStr(buf);
998 if (!setLocationTy(&(supp->caller3), &(supp->caller3_ty)))
999 goto syntax_error;
1000
1001 eof = getLine ( fd, buf, N_BUF );
1002 if (eof || !STREQ(buf, "}")) goto syntax_error;
1003 }
sewardjde4a1d02002-03-22 01:27:54 +00001004 }
1005 }
1006
1007 supp->next = vg_suppressions;
1008 vg_suppressions = supp;
1009 }
1010
1011 VG_(close)(fd);
1012 return;
1013
1014 syntax_error:
1015 if (eof) {
1016 VG_(message)(Vg_UserMsg,
1017 "FATAL: in suppressions file `%s': unexpected EOF",
1018 filename );
1019 } else {
1020 VG_(message)(Vg_UserMsg,
1021 "FATAL: in suppressions file `%s': syntax error on: %s",
1022 filename, buf );
1023 }
1024 VG_(close)(fd);
1025 VG_(message)(Vg_UserMsg, "exiting now.");
1026 VG_(exit)(1);
1027
1028# undef N_BUF
1029}
1030
1031
1032void VG_(load_suppressions) ( void )
1033{
1034 Int i;
1035 vg_suppressions = NULL;
1036 for (i = 0; i < VG_(clo_n_suppressions); i++) {
1037 if (VG_(clo_verbosity) > 1) {
1038 VG_(message)(Vg_UserMsg, "Reading suppressions file: %s",
1039 VG_(clo_suppressions)[i] );
1040 }
1041 load_one_suppressions_file( VG_(clo_suppressions)[i] );
1042 }
1043}
1044
1045
1046/* Does an error context match a suppression? ie is this a
1047 suppressible error? If so, return a pointer to the Suppression
1048 record, otherwise NULL.
1049 Tries to minimise the number of calls to what_fn_is_this since they
1050 are expensive.
1051*/
1052static Suppression* is_suppressible_error ( ErrContext* ec )
1053{
1054# define STREQ(s1,s2) (s1 != NULL && s2 != NULL \
1055 && VG_(strcmp)((s1),(s2))==0)
1056
1057 Char caller0_obj[M_VG_ERRTXT];
1058 Char caller0_fun[M_VG_ERRTXT];
1059 Char caller1_obj[M_VG_ERRTXT];
1060 Char caller1_fun[M_VG_ERRTXT];
1061 Char caller2_obj[M_VG_ERRTXT];
1062 Char caller2_fun[M_VG_ERRTXT];
1063 Char caller3_obj[M_VG_ERRTXT];
1064 Char caller3_fun[M_VG_ERRTXT];
1065
1066 Suppression* su;
1067 Int su_size;
1068
1069 /* vg_what_fn_or_object_is_this returns:
1070 <function_name> or
1071 <object_name> or
1072 ???
1073 so the strings in the suppression file should match these.
1074 */
1075
1076 /* Initialise these strs so they are always safe to compare, even
1077 if what_fn_or_object_is_this doesn't write anything to them. */
1078 caller0_obj[0] = caller1_obj[0] = caller2_obj[0] = caller3_obj[0] = 0;
1079 caller0_fun[0] = caller1_fun[0] = caller2_obj[0] = caller3_obj[0] = 0;
1080
1081 VG_(what_obj_and_fun_is_this)
1082 ( ec->where->eips[0], caller0_obj, M_VG_ERRTXT,
1083 caller0_fun, M_VG_ERRTXT );
1084 VG_(what_obj_and_fun_is_this)
1085 ( ec->where->eips[1], caller1_obj, M_VG_ERRTXT,
1086 caller1_fun, M_VG_ERRTXT );
1087
1088 if (VG_(clo_backtrace_size) > 2) {
1089 VG_(what_obj_and_fun_is_this)
1090 ( ec->where->eips[2], caller2_obj, M_VG_ERRTXT,
1091 caller2_fun, M_VG_ERRTXT );
1092
1093 if (VG_(clo_backtrace_size) > 3) {
1094 VG_(what_obj_and_fun_is_this)
1095 ( ec->where->eips[3], caller3_obj, M_VG_ERRTXT,
1096 caller3_fun, M_VG_ERRTXT );
1097 }
1098 }
1099
1100 /* See if the error context matches any suppression. */
1101 for (su = vg_suppressions; su != NULL; su = su->next) {
1102 switch (su->skind) {
1103 case FreeS:
1104 case Param: case Value0: su_size = 0; break;
1105 case Value1: case Addr1: su_size = 1; break;
1106 case Value2: case Addr2: su_size = 2; break;
1107 case Value4: case Addr4: su_size = 4; break;
1108 case Value8: case Addr8: su_size = 8; break;
1109 default: VG_(panic)("errcontext_matches_suppression");
1110 }
1111 switch (su->skind) {
1112 case Param:
1113 if (ec->ekind != ParamErr) continue;
1114 if (!STREQ(su->param, ec->syscall_param)) continue;
1115 break;
1116 case Value0: case Value1: case Value2: case Value4: case Value8:
1117 if (ec->ekind != ValueErr) continue;
1118 if (ec->size != su_size) continue;
1119 break;
1120 case Addr1: case Addr2: case Addr4: case Addr8:
1121 if (ec->ekind != AddrErr) continue;
1122 if (ec->size != su_size) continue;
1123 break;
1124 case FreeS:
1125 if (ec->ekind != FreeErr && ec->ekind != FreeMismatchErr) continue;
1126 break;
1127 }
1128
1129 switch (su->caller0_ty) {
1130 case ObjName: if (!VG_(stringMatch)(su->caller0,
1131 caller0_obj)) continue;
1132 break;
1133 case FunName: if (!VG_(stringMatch)(su->caller0,
1134 caller0_fun)) continue;
1135 break;
1136 default: goto baaaad;
1137 }
1138
sewardj0873c942002-03-24 09:45:26 +00001139 if (su->caller1 != NULL) {
1140 vg_assert(VG_(clo_backtrace_size) >= 2);
1141 switch (su->caller1_ty) {
1142 case ObjName: if (!VG_(stringMatch)(su->caller1,
1143 caller1_obj)) continue;
1144 break;
1145 case FunName: if (!VG_(stringMatch)(su->caller1,
1146 caller1_fun)) continue;
1147 break;
1148 default: goto baaaad;
1149 }
sewardjde4a1d02002-03-22 01:27:54 +00001150 }
1151
1152 if (VG_(clo_backtrace_size) > 2 && su->caller2 != NULL) {
1153 switch (su->caller2_ty) {
1154 case ObjName: if (!VG_(stringMatch)(su->caller2,
1155 caller2_obj)) continue;
1156 break;
1157 case FunName: if (!VG_(stringMatch)(su->caller2,
1158 caller2_fun)) continue;
1159 break;
1160 default: goto baaaad;
1161 }
1162 }
1163
1164 if (VG_(clo_backtrace_size) > 3 && su->caller3 != NULL) {
1165 switch (su->caller3_ty) {
1166 case ObjName: if (!VG_(stringMatch)(su->caller3,
1167 caller3_obj)) continue;
1168 break;
1169 case FunName: if (!VG_(stringMatch)(su->caller3,
1170 caller3_fun)) continue;
1171 break;
1172 default: goto baaaad;
1173 }
1174 }
1175
1176 return su;
1177 }
1178
1179 return NULL;
1180
1181 baaaad:
1182 VG_(panic)("is_suppressible_error");
1183
1184# undef STREQ
1185}
1186
1187/*--------------------------------------------------------------------*/
1188/*--- end vg_errcontext.c ---*/
1189/*--------------------------------------------------------------------*/