blob: 29d8b2c9de3c20ae5d84cae6966a89192ed556f2 [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
12 Julian_Seward@muraroa.demon.co.uk
13
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of the
17 License, or (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful, but
20 WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 02111-1307, USA.
28
29 The GNU General Public License is contained in the file LICENSE.
30*/
31
32#include "vg_include.h"
33#include "vg_constants.h"
34
35
36/*------------------------------------------------------------*/
37/*--- Defns ---*/
38/*------------------------------------------------------------*/
39
40/* Suppression is a type describing an error which we want to
41 suppress, ie, not show the user, usually because it is caused by a
42 problem in a library which we can't fix, replace or work around.
43 Suppressions are read from a file at startup time, specified by
44 vg_clo_suppressions, and placed in the vg_suppressions list. This
45 gives flexibility so that new suppressions can be added to the file
46 as and when needed.
47*/
48typedef
49 enum {
50 /* Bad syscall params */
51 Param,
52 /* Use of invalid values of given size */
53 Value0, Value1, Value2, Value4, Value8,
54 /* Invalid read/write attempt at given size */
55 Addr1, Addr2, Addr4, Addr8,
56 /* Invalid or mismatching free */
57 FreeS
58 }
59 SuppressionKind;
60
61
62/* For each caller specified for a suppression, record the nature of
63 the caller name. */
64typedef
65 enum {
66 /* Name is of an shared object file. */
67 ObjName,
68 /* Name is of a function. */
69 FunName
70 }
71 SuppressionLocTy;
72
73
74/* A complete suppression record. */
75typedef
76 struct _Suppression {
77 struct _Suppression* next;
78 /* The number of times this error has been suppressed. */
79 Int count;
80 /* The name by which the suppression is referred to. */
81 Char* sname;
82 /* What kind of suppression. */
83 SuppressionKind skind;
84 /* Name of syscall param if skind==Param */
85 Char* param;
86 /* Name of fn where err occurs, and immediate caller (mandatory). */
87 SuppressionLocTy caller0_ty;
88 Char* caller0;
89 SuppressionLocTy caller1_ty;
90 Char* caller1;
91 /* Optional extra callers. */
92 SuppressionLocTy caller2_ty;
93 Char* caller2;
94 SuppressionLocTy caller3_ty;
95 Char* caller3;
96 }
97 Suppression;
98
99
100/* ErrContext is a type for recording just enough info to generate an
101 error report for an illegal memory access. The idea is that
102 (typically) the same few points in the program generate thousands
103 of illegal accesses, and we don't want to spew out a fresh error
104 message for each one. Instead, we use these structures to common
105 up duplicates.
106*/
107
108/* What kind of error it is. */
109typedef
110 enum { ValueErr, AddrErr,
111 ParamErr, UserErr, /* behaves like an anonymous ParamErr */
112 FreeErr, FreeMismatchErr }
113 ErrKind;
114
115/* What kind of memory access is involved in the error? */
116typedef
117 enum { ReadAxs, WriteAxs, ExecAxs }
118 AxsKind;
119
120/* Top-level struct for recording errors. */
121typedef
122 struct _ErrContext {
123 /* ALL */
124 struct _ErrContext* next;
125 /* ALL */
126 /* NULL if unsuppressed; or ptr to suppression record. */
127 Suppression* supp;
128 /* ALL */
129 Int count;
130 /* ALL */
131 ErrKind ekind;
132 /* ALL */
133 ExeContext* where;
134 /* Addr */
135 AxsKind axskind;
136 /* Addr, Value */
137 Int size;
138 /* Addr, Free, Param, User */
139 Addr addr;
140 /* Addr, Free, Param, User */
141 AddrInfo addrinfo;
142 /* Param */
143 Char* syscall_param;
144 /* Param, User */
145 Bool isWriteableLack;
146 }
147 ErrContext;
148
149/* The list of error contexts found, both suppressed and unsuppressed.
150 Initially empty, and grows as errors are detected. */
151static ErrContext* vg_err_contexts = NULL;
152
153/* The list of suppression directives, as read from the specified
154 suppressions file. */
155static Suppression* vg_suppressions = NULL;
156
157/* Running count of unsuppressed errors detected. */
158static UInt vg_n_errs_found = 0;
159
160/* Running count of suppressed errors detected. */
161static UInt vg_n_errs_suppressed = 0;
162
163/* forwards ... */
164static Suppression* is_suppressible_error ( ErrContext* ec );
165
166
167/*------------------------------------------------------------*/
168/*--- Helper fns ---*/
169/*------------------------------------------------------------*/
170
171
172static void clear_AddrInfo ( AddrInfo* ai )
173{
174 ai->akind = Unknown;
175 ai->blksize = 0;
176 ai->rwoffset = 0;
177 ai->lastchange = NULL;
178}
179
180static void clear_ErrContext ( ErrContext* ec )
181{
182 ec->next = NULL;
183 ec->supp = NULL;
184 ec->count = 0;
185 ec->ekind = ValueErr;
186 ec->where = NULL;
187 ec->axskind = ReadAxs;
188 ec->size = 0;
189 ec->addr = 0;
190 clear_AddrInfo ( &ec->addrinfo );
191 ec->syscall_param = NULL;
192 ec->isWriteableLack = False;
193}
194
195
196static __inline__
197Bool vg_eq_ExeContext ( Bool top_2_only,
198 ExeContext* e1, ExeContext* e2 )
199{
200 /* Note that frames after the 4th are always ignored. */
201 if (top_2_only) {
202 return VG_(eq_ExeContext_top2(e1, e2));
203 } else {
204 return VG_(eq_ExeContext_top4(e1, e2));
205 }
206}
207
208
209static Bool eq_AddrInfo ( Bool cheap_addr_cmp,
210 AddrInfo* ai1, AddrInfo* ai2 )
211{
212 if (ai1->akind != ai2->akind)
213 return False;
214 if (ai1->akind == Freed || ai1->akind == Mallocd) {
215 if (ai1->blksize != ai2->blksize)
216 return False;
217 if (!vg_eq_ExeContext(cheap_addr_cmp,
218 ai1->lastchange, ai2->lastchange))
219 return False;
220 }
221 return True;
222}
223
224/* Compare error contexts, to detect duplicates. Note that if they
225 are otherwise the same, the faulting addrs and associated rwoffsets
226 are allowed to be different. */
227
228static Bool eq_ErrContext ( Bool cheap_addr_cmp,
229 ErrContext* e1, ErrContext* e2 )
230{
231 if (e1->ekind != e2->ekind)
232 return False;
233 if (!vg_eq_ExeContext(cheap_addr_cmp, e1->where, e2->where))
234 return False;
235
236 switch (e1->ekind) {
237 case UserErr:
238 case ParamErr:
239 if (e1->isWriteableLack != e2->isWriteableLack) return False;
240 if (e1->ekind == ParamErr
241 && 0 != VG_(strcmp)(e1->syscall_param, e2->syscall_param))
242 return False;
243 return True;
244 case FreeErr:
245 case FreeMismatchErr:
246 if (e1->addr != e2->addr) return False;
247 if (!eq_AddrInfo(cheap_addr_cmp, &e1->addrinfo, &e2->addrinfo))
248 return False;
249 return True;
250 case AddrErr:
251 if (e1->axskind != e2->axskind) return False;
252 if (e1->size != e2->size) return False;
253 if (!eq_AddrInfo(cheap_addr_cmp, &e1->addrinfo, &e2->addrinfo))
254 return False;
255 return True;
256 case ValueErr:
257 if (e1->size != e2->size) return False;
258 return True;
259 default:
260 VG_(panic)("eq_ErrContext");
261 }
262}
263
264static void pp_AddrInfo ( Addr a, AddrInfo* ai )
265{
266 switch (ai->akind) {
267 case Stack:
268 VG_(message)(Vg_UserMsg, " Address 0x%x is on the stack", a);
269 break;
270 case Unknown:
271 VG_(message)(Vg_UserMsg,
272 " Address 0x%x is not stack'd, malloc'd or free'd", a);
273 break;
274 case Freed: case Mallocd: case UserG: case UserS: {
275 UInt delta;
276 UChar* relative;
277 if (ai->rwoffset < 0) {
278 delta = (UInt)(- ai->rwoffset);
279 relative = "before";
280 } else if (ai->rwoffset >= ai->blksize) {
281 delta = ai->rwoffset - ai->blksize;
282 relative = "after";
283 } else {
284 delta = ai->rwoffset;
285 relative = "inside";
286 }
287 if (ai->akind == UserS) {
288 VG_(message)(Vg_UserMsg,
289 " Address 0x%x is %d bytes %s a %d-byte stack red-zone created",
290 a, delta, relative,
291 ai->blksize );
292 } else {
293 VG_(message)(Vg_UserMsg,
294 " Address 0x%x is %d bytes %s a block of size %d %s",
295 a, delta, relative,
296 ai->blksize,
297 ai->akind==Mallocd ? "alloc'd"
298 : ai->akind==Freed ? "free'd"
299 : "client-defined");
300 }
301 VG_(pp_ExeContext)(ai->lastchange);
302 break;
303 }
304 default:
305 VG_(panic)("pp_AddrInfo");
306 }
307}
308
309static void pp_ErrContext ( ErrContext* ec, Bool printCount )
310{
311 if (printCount)
312 VG_(message)(Vg_UserMsg, "Observed %d times:", ec->count );
313 switch (ec->ekind) {
314 case ValueErr:
315 if (ec->size == 0) {
sewardja7dc7952002-03-24 11:29:13 +0000316 VG_(message)(
317 Vg_UserMsg,
318 "Conditional jump or move depends on uninitialised value(s)");
sewardjde4a1d02002-03-22 01:27:54 +0000319 } else {
320 VG_(message)(Vg_UserMsg,
321 "Use of uninitialised value of size %d",
322 ec->size);
323 }
324 VG_(pp_ExeContext)(ec->where);
325 break;
326 case AddrErr:
327 switch (ec->axskind) {
328 case ReadAxs:
329 VG_(message)(Vg_UserMsg, "Invalid read of size %d",
330 ec->size );
331 break;
332 case WriteAxs:
333 VG_(message)(Vg_UserMsg, "Invalid write of size %d",
334 ec->size );
335 break;
336 case ExecAxs:
337 VG_(message)(Vg_UserMsg, "Jump to the invalid address "
338 "stated on the next line");
339 break;
340 default:
341 VG_(panic)("pp_ErrContext(axskind)");
342 }
343 VG_(pp_ExeContext)(ec->where);
344 pp_AddrInfo(ec->addr, &ec->addrinfo);
345 break;
346 case FreeErr:
347 VG_(message)(Vg_UserMsg,"Invalid free() / delete / delete[]");
348 /* fall through */
349 case FreeMismatchErr:
350 if (ec->ekind == FreeMismatchErr)
351 VG_(message)(Vg_UserMsg,
352 "Mismatched free() / delete / delete []");
353 VG_(pp_ExeContext)(ec->where);
354 pp_AddrInfo(ec->addr, &ec->addrinfo);
355 break;
356 case ParamErr:
357 if (ec->isWriteableLack) {
358 VG_(message)(Vg_UserMsg,
359 "Syscall param %s contains unaddressable byte(s)",
360 ec->syscall_param );
361 } else {
362 VG_(message)(Vg_UserMsg,
363 "Syscall param %s contains uninitialised or "
364 "unaddressable byte(s)",
365 ec->syscall_param);
366 }
367 VG_(pp_ExeContext)(ec->where);
368 pp_AddrInfo(ec->addr, &ec->addrinfo);
369 break;
370 case UserErr:
371 if (ec->isWriteableLack) {
372 VG_(message)(Vg_UserMsg,
373 "Unaddressable byte(s) found during client check request");
374 } else {
375 VG_(message)(Vg_UserMsg,
376 "Uninitialised or "
377 "unaddressable byte(s) found during client check request");
378 }
379 VG_(pp_ExeContext)(ec->where);
380 pp_AddrInfo(ec->addr, &ec->addrinfo);
381 break;
382 default:
383 VG_(panic)("pp_ErrContext");
384 }
385}
386
387
388/* Figure out if we want to attach for GDB for this error, possibly
389 by asking the user. */
390static
391Bool vg_is_GDB_attach_requested ( void )
392{
393 Char ch, ch2;
394 Int res;
395
396 if (VG_(clo_GDB_attach) == False)
397 return False;
398
399 VG_(message)(Vg_UserMsg, "");
400
401 again:
402 VG_(printf)(
403 "==%d== "
404 "---- Attach to GDB ? --- [Return/N/n/Y/y/C/c] ---- ",
405 VG_(getpid)()
406 );
407
408 res = VG_(read)(0 /*stdin*/, &ch, 1);
409 if (res != 1) goto ioerror;
410 /* res == 1 */
411 if (ch == '\n') return False;
412 if (ch != 'N' && ch != 'n' && ch != 'Y' && ch != 'y'
413 && ch != 'C' && ch != 'c') goto again;
414
415 res = VG_(read)(0 /*stdin*/, &ch2, 1);
416 if (res != 1) goto ioerror;
417 if (ch2 != '\n') goto again;
418
419 /* No, don't want to attach. */
420 if (ch == 'n' || ch == 'N') return False;
421 /* Yes, want to attach. */
422 if (ch == 'y' || ch == 'Y') return True;
423 /* No, don't want to attach, and don't ask again either. */
424 vg_assert(ch == 'c' || ch == 'C');
425
426 ioerror:
427 VG_(clo_GDB_attach) = False;
428 return False;
429}
430
431
432/* Top-level entry point to the error management subsystem. All
433 detected errors are notified here; this routine decides if/when the
434 user should see the error. */
435static void VG_(maybe_add_context) ( ErrContext* ec )
436{
437 ErrContext* p;
438 ErrContext* p_prev;
439 Bool cheap_addr_cmp = False;
440 static Bool is_first_shown_context = True;
441 static Bool stopping_message = False;
442 static Bool slowdown_message = False;
443 static Int vg_n_errs_shown = 0;
444
445 /* After M_VG_COLLECT_NO_ERRORS_AFTER different errors have been
446 found, just refuse to collect any more. */
447 if (vg_n_errs_shown >= M_VG_COLLECT_NO_ERRORS_AFTER) {
448 if (!stopping_message) {
449 VG_(message)(Vg_UserMsg, "");
450 VG_(message)(Vg_UserMsg,
451 "More than %d errors detected. I'm not reporting any more.",
452 M_VG_COLLECT_NO_ERRORS_AFTER);
453 VG_(message)(Vg_UserMsg,
454 "Final error counts may be inaccurate. Go fix your program!");
455 VG_(message)(Vg_UserMsg, "");
456 stopping_message = True;
457 }
458 return;
459 }
460
461 /* After M_VG_COLLECT_ERRORS_SLOWLY_AFTER different errors have
462 been found, be much more conservative about collecting new
463 ones. */
464 if (vg_n_errs_shown >= M_VG_COLLECT_ERRORS_SLOWLY_AFTER) {
465 cheap_addr_cmp = True;
466 if (!slowdown_message) {
467 VG_(message)(Vg_UserMsg, "");
468 VG_(message)(Vg_UserMsg,
469 "More than %d errors detected. Subsequent errors",
470 M_VG_COLLECT_ERRORS_SLOWLY_AFTER);
471 VG_(message)(Vg_UserMsg,
472 "will still be recorded, but in less detail than before.");
473 slowdown_message = True;
474 }
475 }
476
477
478 /* First, see if we've got an error record matching this one. */
479 p = vg_err_contexts;
480 p_prev = NULL;
481 while (p != NULL) {
482 if (eq_ErrContext(cheap_addr_cmp, p, ec)) {
483 /* Found it. */
484 p->count++;
485 if (p->supp != NULL) {
486 /* Deal correctly with suppressed errors. */
487 p->supp->count++;
488 vg_n_errs_suppressed++;
489 } else {
490 vg_n_errs_found++;
491 }
492
493 /* Move p to the front of the list so that future searches
494 for it are faster. */
495 if (p_prev != NULL) {
496 vg_assert(p_prev->next == p);
497 p_prev->next = p->next;
498 p->next = vg_err_contexts;
499 vg_err_contexts = p;
500 }
501 return;
502 }
503 p_prev = p;
504 p = p->next;
505 }
506
507 /* Didn't see it. Copy and add. */
508
509 /* OK, we're really going to collect it. */
510
511 p = VG_(malloc)(VG_AR_ERRCTXT, sizeof(ErrContext));
512 *p = *ec;
513 p->next = vg_err_contexts;
514 p->supp = is_suppressible_error(ec);
515 vg_err_contexts = p;
516 if (p->supp == NULL) {
517 vg_n_errs_found++;
518 if (!is_first_shown_context)
519 VG_(message)(Vg_UserMsg, "");
520 pp_ErrContext(p, False);
521 is_first_shown_context = False;
522 vg_n_errs_shown++;
523 /* Perhaps we want a GDB attach at this point? */
524 if (vg_is_GDB_attach_requested()) {
525 VG_(swizzle_esp_then_start_GDB)();
526 }
527 } else {
528 vg_n_errs_suppressed++;
529 p->supp->count++;
530 }
531}
532
533
534
535
536/*------------------------------------------------------------*/
537/*--- Exported fns ---*/
538/*------------------------------------------------------------*/
539
sewardj8c824512002-04-14 04:16:48 +0000540/* These are all called from generated code, so that the %EIP/%EBP
541 values that we need in order to create proper error messages are
542 picked up out of VG_(baseBlock) rather than from the thread table
543 (vg_threads in vg_scheduler.c). */
544
sewardjde4a1d02002-03-22 01:27:54 +0000545void VG_(record_value_error) ( Int size )
546{
547 ErrContext ec;
548 clear_ErrContext( &ec );
549 ec.count = 1;
550 ec.next = NULL;
sewardj8c824512002-04-14 04:16:48 +0000551 ec.where = VG_(get_ExeContext)( False, VG_(baseBlock)[VGOFF_(m_eip)],
552 VG_(baseBlock)[VGOFF_(m_ebp)] );
sewardjde4a1d02002-03-22 01:27:54 +0000553 ec.ekind = ValueErr;
554 ec.size = size;
555 VG_(maybe_add_context) ( &ec );
556}
557
558void VG_(record_address_error) ( Addr a, Int size, Bool isWrite )
559{
560 ErrContext ec;
561
562 /* If this is caused by an access immediately below %ESP, and the
563 user asks nicely, we just ignore it. */
sewardj8c824512002-04-14 04:16:48 +0000564 if (VG_(clo_workaround_gcc296_bugs)
565 && VG_(is_just_below_ESP)( VG_(baseBlock)[VGOFF_(m_esp)], a ))
sewardjde4a1d02002-03-22 01:27:54 +0000566 return;
567
568 clear_ErrContext( &ec );
569 ec.count = 1;
570 ec.next = NULL;
sewardj8c824512002-04-14 04:16:48 +0000571 ec.where = VG_(get_ExeContext)( False, VG_(baseBlock)[VGOFF_(m_eip)],
572 VG_(baseBlock)[VGOFF_(m_ebp)] );
sewardjde4a1d02002-03-22 01:27:54 +0000573 ec.ekind = AddrErr;
574 ec.axskind = isWrite ? WriteAxs : ReadAxs;
575 ec.size = size;
576 ec.addr = a;
577 VG_(describe_addr) ( a, &ec.addrinfo );
578 VG_(maybe_add_context) ( &ec );
579}
580
581void VG_(record_jump_error) ( Addr a )
582{
583 ErrContext ec;
584 clear_ErrContext( &ec );
585 ec.count = 1;
586 ec.next = NULL;
sewardj8c824512002-04-14 04:16:48 +0000587 ec.where = VG_(get_ExeContext)( False, VG_(baseBlock)[VGOFF_(m_eip)],
588 VG_(baseBlock)[VGOFF_(m_ebp)] );
sewardjde4a1d02002-03-22 01:27:54 +0000589 ec.ekind = AddrErr;
590 ec.axskind = ExecAxs;
591 ec.addr = a;
592 VG_(describe_addr) ( a, &ec.addrinfo );
593 VG_(maybe_add_context) ( &ec );
594}
595
596void VG_(record_free_error) ( Addr a )
597{
598 ErrContext ec;
599 clear_ErrContext( &ec );
600 ec.count = 1;
601 ec.next = NULL;
sewardj8c824512002-04-14 04:16:48 +0000602 ec.where = VG_(get_ExeContext)( True, VG_(baseBlock)[VGOFF_(m_eip)],
603 VG_(baseBlock)[VGOFF_(m_ebp)] );
sewardjde4a1d02002-03-22 01:27:54 +0000604 ec.ekind = FreeErr;
605 ec.addr = a;
606 VG_(describe_addr) ( a, &ec.addrinfo );
607 VG_(maybe_add_context) ( &ec );
608}
609
610void VG_(record_freemismatch_error) ( Addr a )
611{
612 ErrContext ec;
613 clear_ErrContext( &ec );
614 ec.count = 1;
615 ec.next = NULL;
sewardj8c824512002-04-14 04:16:48 +0000616 ec.where = VG_(get_ExeContext)( True, VG_(baseBlock)[VGOFF_(m_eip)],
617 VG_(baseBlock)[VGOFF_(m_ebp)] );
sewardjde4a1d02002-03-22 01:27:54 +0000618 ec.ekind = FreeMismatchErr;
619 ec.addr = a;
620 VG_(describe_addr) ( a, &ec.addrinfo );
621 VG_(maybe_add_context) ( &ec );
622}
623
sewardj8c824512002-04-14 04:16:48 +0000624/* These two are called not from generated code but in response to
625 requests passed back to the scheduler. So we pick up %EIP/%EBP
626 values from the stored thread state, not from VG_(baseBlock). */
627
628void VG_(record_param_err) ( ThreadState* tst, Addr a, Bool isWriteLack,
629 Char* msg )
sewardjde4a1d02002-03-22 01:27:54 +0000630{
631 ErrContext ec;
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, tst->m_eip, tst->m_ebp );
sewardjde4a1d02002-03-22 01:27:54 +0000636 ec.ekind = ParamErr;
637 ec.addr = a;
638 VG_(describe_addr) ( a, &ec.addrinfo );
639 ec.syscall_param = msg;
640 ec.isWriteableLack = isWriteLack;
641 VG_(maybe_add_context) ( &ec );
642}
643
644
sewardj8c824512002-04-14 04:16:48 +0000645void VG_(record_user_err) ( ThreadState* tst, Addr a, Bool isWriteLack )
sewardjde4a1d02002-03-22 01:27:54 +0000646{
647 ErrContext ec;
648 clear_ErrContext( &ec );
649 ec.count = 1;
650 ec.next = NULL;
sewardj8c824512002-04-14 04:16:48 +0000651 ec.where = VG_(get_ExeContext)( False, tst->m_eip, tst->m_ebp );
sewardjde4a1d02002-03-22 01:27:54 +0000652 ec.ekind = UserErr;
653 ec.addr = a;
654 VG_(describe_addr) ( a, &ec.addrinfo );
655 ec.isWriteableLack = isWriteLack;
656 VG_(maybe_add_context) ( &ec );
657}
658
659
sewardj8c824512002-04-14 04:16:48 +0000660/*------------------------------*/
661
sewardjde4a1d02002-03-22 01:27:54 +0000662void VG_(show_all_errors) ( void )
663{
664 Int i, n_min;
665 Int n_err_contexts, n_supp_contexts;
666 ErrContext *p, *p_min;
667 Suppression *su;
668 Bool any_supp;
669
670 if (VG_(clo_verbosity) == 0)
671 return;
672
673 n_err_contexts = 0;
674 for (p = vg_err_contexts; p != NULL; p = p->next) {
675 if (p->supp == NULL)
676 n_err_contexts++;
677 }
678
679 n_supp_contexts = 0;
680 for (su = vg_suppressions; su != NULL; su = su->next) {
681 if (su->count > 0)
682 n_supp_contexts++;
683 }
684
685 VG_(message)(Vg_UserMsg,
686 "ERROR SUMMARY: "
687 "%d errors from %d contexts (suppressed: %d from %d)",
688 vg_n_errs_found, n_err_contexts,
689 vg_n_errs_suppressed, n_supp_contexts );
690
691 if (VG_(clo_verbosity) <= 1)
692 return;
693
694 /* Print the contexts in order of increasing error count. */
695 for (i = 0; i < n_err_contexts; i++) {
696 n_min = (1 << 30) - 1;
697 p_min = NULL;
698 for (p = vg_err_contexts; p != NULL; p = p->next) {
699 if (p->supp != NULL) continue;
700 if (p->count < n_min) {
701 n_min = p->count;
702 p_min = p;
703 }
704 }
705 if (p_min == NULL) VG_(panic)("pp_AllErrContexts");
706
707 VG_(message)(Vg_UserMsg, "");
708 VG_(message)(Vg_UserMsg, "%d errors in context %d of %d:",
709 p_min->count,
710 i+1, n_err_contexts);
711 pp_ErrContext( p_min, False );
712
713 if ((i+1 == VG_(clo_dump_error))) {
714 VG_(translate) ( p_min->where->eips[0], NULL, NULL, NULL );
715 }
716
717 p_min->count = 1 << 30;
718 }
719
720 if (n_supp_contexts > 0)
721 VG_(message)(Vg_DebugMsg, "");
722 any_supp = False;
723 for (su = vg_suppressions; su != NULL; su = su->next) {
724 if (su->count > 0) {
725 any_supp = True;
726 VG_(message)(Vg_DebugMsg, "supp: %4d %s", su->count,
727 su->sname);
728 }
729 }
730
731 if (n_err_contexts > 0) {
732 if (any_supp)
733 VG_(message)(Vg_UserMsg, "");
734 VG_(message)(Vg_UserMsg,
735 "IN SUMMARY: "
736 "%d errors from %d contexts (suppressed: %d from %d)",
737 vg_n_errs_found, n_err_contexts,
738 vg_n_errs_suppressed,
739 n_supp_contexts );
740 VG_(message)(Vg_UserMsg, "");
741 }
742}
743
744/*------------------------------------------------------------*/
745/*--- Standard suppressions ---*/
746/*------------------------------------------------------------*/
747
748/* Get a non-blank, non-comment line of at most nBuf chars from fd.
749 Skips leading spaces on the line. Return True if EOF was hit instead.
750*/
751
752#define VG_ISSPACE(ch) (((ch)==' ') || ((ch)=='\n') || ((ch)=='\t'))
753
754static Bool getLine ( Int fd, Char* buf, Int nBuf )
755{
756 Char ch;
757 Int n, i;
758 while (True) {
759 /* First, read until a non-blank char appears. */
760 while (True) {
761 n = VG_(read)(fd, &ch, 1);
762 if (n == 1 && !VG_ISSPACE(ch)) break;
763 if (n == 0) return True;
764 }
765
766 /* Now, read the line into buf. */
767 i = 0;
768 buf[i++] = ch; buf[i] = 0;
769 while (True) {
770 n = VG_(read)(fd, &ch, 1);
771 if (n == 0) return False; /* the next call will return True */
772 if (ch == '\n') break;
773 if (i > 0 && i == nBuf-1) i--;
774 buf[i++] = ch; buf[i] = 0;
775 }
776 while (i > 1 && VG_ISSPACE(buf[i-1])) {
777 i--; buf[i] = 0;
778 };
779
780 /* VG_(printf)("The line is `%s'\n", buf); */
781 /* Ok, we have a line. If a non-comment line, return.
782 If a comment line, start all over again. */
783 if (buf[0] != '#') return False;
784 }
785}
786
787
788/* *p_caller contains the raw name of a caller, supposedly either
789 fun:some_function_name or
790 obj:some_object_name.
791 Set *p_ty accordingly and advance *p_caller over the descriptor
792 (fun: or obj:) part.
793 Returns False if failed.
794*/
795static Bool setLocationTy ( Char** p_caller, SuppressionLocTy* p_ty )
796{
797 if (VG_(strncmp)(*p_caller, "fun:", 4) == 0) {
798 (*p_caller) += 4;
799 *p_ty = FunName;
800 return True;
801 }
802 if (VG_(strncmp)(*p_caller, "obj:", 4) == 0) {
803 (*p_caller) += 4;
804 *p_ty = ObjName;
805 return True;
806 }
807 VG_(printf)("location should start with fun: or obj:\n");
808 return False;
809}
810
811
812/* Read suppressions from the file specified in vg_clo_suppressions
813 and place them in the suppressions list. If there's any difficulty
814 doing this, just give up -- there's no point in trying to recover.
815*/
816#define STREQ(s1,s2) (s1 != NULL && s2 != NULL \
817 && VG_(strcmp)((s1),(s2))==0)
818
819static Char* copyStr ( Char* str )
820{
821 Int n, i;
822 Char* str2;
823 n = VG_(strlen)(str);
824 str2 = VG_(malloc)(VG_AR_PRIVATE, n+1);
825 vg_assert(n > 0);
826 for (i = 0; i < n+1; i++) str2[i] = str[i];
827 return str2;
828}
829
830static void load_one_suppressions_file ( Char* filename )
831{
832# define N_BUF 200
833 Int fd;
834 Bool eof;
835 Char buf[N_BUF+1];
836 fd = VG_(open_read)( filename );
837 if (fd == -1) {
838 VG_(message)(Vg_UserMsg,
839 "FATAL: can't open suppressions file `%s'",
840 filename );
841 VG_(exit)(1);
842 }
843
844 while (True) {
845 Suppression* supp;
846 supp = VG_(malloc)(VG_AR_PRIVATE, sizeof(Suppression));
847 supp->count = 0;
848 supp->param = supp->caller0 = supp->caller1
849 = supp->caller2 = supp->caller3 = NULL;
850
851 eof = getLine ( fd, buf, N_BUF );
852 if (eof) break;
853
854 if (!STREQ(buf, "{")) goto syntax_error;
855
856 eof = getLine ( fd, buf, N_BUF );
857 if (eof || STREQ(buf, "}")) goto syntax_error;
858 supp->sname = copyStr(buf);
859
860 eof = getLine ( fd, buf, N_BUF );
861 if (eof) goto syntax_error;
862 else if (STREQ(buf, "Param")) supp->skind = Param;
sewardja7dc7952002-03-24 11:29:13 +0000863 else if (STREQ(buf, "Value0")) supp->skind = Value0; /* backwards compat */
864 else if (STREQ(buf, "Cond")) supp->skind = Value0;
sewardjde4a1d02002-03-22 01:27:54 +0000865 else if (STREQ(buf, "Value1")) supp->skind = Value1;
866 else if (STREQ(buf, "Value2")) supp->skind = Value2;
867 else if (STREQ(buf, "Value4")) supp->skind = Value4;
868 else if (STREQ(buf, "Value8")) supp->skind = Value8;
869 else if (STREQ(buf, "Addr1")) supp->skind = Addr1;
870 else if (STREQ(buf, "Addr2")) supp->skind = Addr2;
871 else if (STREQ(buf, "Addr4")) supp->skind = Addr4;
872 else if (STREQ(buf, "Addr8")) supp->skind = Addr8;
873 else if (STREQ(buf, "Free")) supp->skind = FreeS;
874 else goto syntax_error;
875
876 if (supp->skind == Param) {
877 eof = getLine ( fd, buf, N_BUF );
878 if (eof) goto syntax_error;
879 supp->param = copyStr(buf);
880 }
881
882 eof = getLine ( fd, buf, N_BUF );
883 if (eof) goto syntax_error;
884 supp->caller0 = copyStr(buf);
885 if (!setLocationTy(&(supp->caller0), &(supp->caller0_ty)))
886 goto syntax_error;
887
888 eof = getLine ( fd, buf, N_BUF );
889 if (eof) goto syntax_error;
sewardjde4a1d02002-03-22 01:27:54 +0000890 if (!STREQ(buf, "}")) {
sewardj0873c942002-03-24 09:45:26 +0000891 supp->caller1 = copyStr(buf);
892 if (!setLocationTy(&(supp->caller1), &(supp->caller1_ty)))
sewardjde4a1d02002-03-22 01:27:54 +0000893 goto syntax_error;
sewardj0873c942002-03-24 09:45:26 +0000894
sewardjde4a1d02002-03-22 01:27:54 +0000895 eof = getLine ( fd, buf, N_BUF );
896 if (eof) goto syntax_error;
897 if (!STREQ(buf, "}")) {
sewardj0873c942002-03-24 09:45:26 +0000898 supp->caller2 = copyStr(buf);
899 if (!setLocationTy(&(supp->caller2), &(supp->caller2_ty)))
sewardjde4a1d02002-03-22 01:27:54 +0000900 goto syntax_error;
sewardj0873c942002-03-24 09:45:26 +0000901
sewardjde4a1d02002-03-22 01:27:54 +0000902 eof = getLine ( fd, buf, N_BUF );
sewardj0873c942002-03-24 09:45:26 +0000903 if (eof) goto syntax_error;
904 if (!STREQ(buf, "}")) {
905 supp->caller3 = copyStr(buf);
906 if (!setLocationTy(&(supp->caller3), &(supp->caller3_ty)))
907 goto syntax_error;
908
909 eof = getLine ( fd, buf, N_BUF );
910 if (eof || !STREQ(buf, "}")) goto syntax_error;
911 }
sewardjde4a1d02002-03-22 01:27:54 +0000912 }
913 }
914
915 supp->next = vg_suppressions;
916 vg_suppressions = supp;
917 }
918
919 VG_(close)(fd);
920 return;
921
922 syntax_error:
923 if (eof) {
924 VG_(message)(Vg_UserMsg,
925 "FATAL: in suppressions file `%s': unexpected EOF",
926 filename );
927 } else {
928 VG_(message)(Vg_UserMsg,
929 "FATAL: in suppressions file `%s': syntax error on: %s",
930 filename, buf );
931 }
932 VG_(close)(fd);
933 VG_(message)(Vg_UserMsg, "exiting now.");
934 VG_(exit)(1);
935
936# undef N_BUF
937}
938
939
940void VG_(load_suppressions) ( void )
941{
942 Int i;
943 vg_suppressions = NULL;
944 for (i = 0; i < VG_(clo_n_suppressions); i++) {
945 if (VG_(clo_verbosity) > 1) {
946 VG_(message)(Vg_UserMsg, "Reading suppressions file: %s",
947 VG_(clo_suppressions)[i] );
948 }
949 load_one_suppressions_file( VG_(clo_suppressions)[i] );
950 }
951}
952
953
954/* Does an error context match a suppression? ie is this a
955 suppressible error? If so, return a pointer to the Suppression
956 record, otherwise NULL.
957 Tries to minimise the number of calls to what_fn_is_this since they
958 are expensive.
959*/
960static Suppression* is_suppressible_error ( ErrContext* ec )
961{
962# define STREQ(s1,s2) (s1 != NULL && s2 != NULL \
963 && VG_(strcmp)((s1),(s2))==0)
964
965 Char caller0_obj[M_VG_ERRTXT];
966 Char caller0_fun[M_VG_ERRTXT];
967 Char caller1_obj[M_VG_ERRTXT];
968 Char caller1_fun[M_VG_ERRTXT];
969 Char caller2_obj[M_VG_ERRTXT];
970 Char caller2_fun[M_VG_ERRTXT];
971 Char caller3_obj[M_VG_ERRTXT];
972 Char caller3_fun[M_VG_ERRTXT];
973
974 Suppression* su;
975 Int su_size;
976
977 /* vg_what_fn_or_object_is_this returns:
978 <function_name> or
979 <object_name> or
980 ???
981 so the strings in the suppression file should match these.
982 */
983
984 /* Initialise these strs so they are always safe to compare, even
985 if what_fn_or_object_is_this doesn't write anything to them. */
986 caller0_obj[0] = caller1_obj[0] = caller2_obj[0] = caller3_obj[0] = 0;
987 caller0_fun[0] = caller1_fun[0] = caller2_obj[0] = caller3_obj[0] = 0;
988
989 VG_(what_obj_and_fun_is_this)
990 ( ec->where->eips[0], caller0_obj, M_VG_ERRTXT,
991 caller0_fun, M_VG_ERRTXT );
992 VG_(what_obj_and_fun_is_this)
993 ( ec->where->eips[1], caller1_obj, M_VG_ERRTXT,
994 caller1_fun, M_VG_ERRTXT );
995
996 if (VG_(clo_backtrace_size) > 2) {
997 VG_(what_obj_and_fun_is_this)
998 ( ec->where->eips[2], caller2_obj, M_VG_ERRTXT,
999 caller2_fun, M_VG_ERRTXT );
1000
1001 if (VG_(clo_backtrace_size) > 3) {
1002 VG_(what_obj_and_fun_is_this)
1003 ( ec->where->eips[3], caller3_obj, M_VG_ERRTXT,
1004 caller3_fun, M_VG_ERRTXT );
1005 }
1006 }
1007
1008 /* See if the error context matches any suppression. */
1009 for (su = vg_suppressions; su != NULL; su = su->next) {
1010 switch (su->skind) {
1011 case FreeS:
1012 case Param: case Value0: su_size = 0; break;
1013 case Value1: case Addr1: su_size = 1; break;
1014 case Value2: case Addr2: su_size = 2; break;
1015 case Value4: case Addr4: su_size = 4; break;
1016 case Value8: case Addr8: su_size = 8; break;
1017 default: VG_(panic)("errcontext_matches_suppression");
1018 }
1019 switch (su->skind) {
1020 case Param:
1021 if (ec->ekind != ParamErr) continue;
1022 if (!STREQ(su->param, ec->syscall_param)) continue;
1023 break;
1024 case Value0: case Value1: case Value2: case Value4: case Value8:
1025 if (ec->ekind != ValueErr) continue;
1026 if (ec->size != su_size) continue;
1027 break;
1028 case Addr1: case Addr2: case Addr4: case Addr8:
1029 if (ec->ekind != AddrErr) continue;
1030 if (ec->size != su_size) continue;
1031 break;
1032 case FreeS:
1033 if (ec->ekind != FreeErr && ec->ekind != FreeMismatchErr) continue;
1034 break;
1035 }
1036
1037 switch (su->caller0_ty) {
1038 case ObjName: if (!VG_(stringMatch)(su->caller0,
1039 caller0_obj)) continue;
1040 break;
1041 case FunName: if (!VG_(stringMatch)(su->caller0,
1042 caller0_fun)) continue;
1043 break;
1044 default: goto baaaad;
1045 }
1046
sewardj0873c942002-03-24 09:45:26 +00001047 if (su->caller1 != NULL) {
1048 vg_assert(VG_(clo_backtrace_size) >= 2);
1049 switch (su->caller1_ty) {
1050 case ObjName: if (!VG_(stringMatch)(su->caller1,
1051 caller1_obj)) continue;
1052 break;
1053 case FunName: if (!VG_(stringMatch)(su->caller1,
1054 caller1_fun)) continue;
1055 break;
1056 default: goto baaaad;
1057 }
sewardjde4a1d02002-03-22 01:27:54 +00001058 }
1059
1060 if (VG_(clo_backtrace_size) > 2 && su->caller2 != NULL) {
1061 switch (su->caller2_ty) {
1062 case ObjName: if (!VG_(stringMatch)(su->caller2,
1063 caller2_obj)) continue;
1064 break;
1065 case FunName: if (!VG_(stringMatch)(su->caller2,
1066 caller2_fun)) continue;
1067 break;
1068 default: goto baaaad;
1069 }
1070 }
1071
1072 if (VG_(clo_backtrace_size) > 3 && su->caller3 != NULL) {
1073 switch (su->caller3_ty) {
1074 case ObjName: if (!VG_(stringMatch)(su->caller3,
1075 caller3_obj)) continue;
1076 break;
1077 case FunName: if (!VG_(stringMatch)(su->caller3,
1078 caller3_fun)) continue;
1079 break;
1080 default: goto baaaad;
1081 }
1082 }
1083
1084 return su;
1085 }
1086
1087 return NULL;
1088
1089 baaaad:
1090 VG_(panic)("is_suppressible_error");
1091
1092# undef STREQ
1093}
1094
1095/*--------------------------------------------------------------------*/
1096/*--- end vg_errcontext.c ---*/
1097/*--------------------------------------------------------------------*/