blob: 42e09b53a51eef91666cb7c1b9291a1051a2ab14 [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) {
316 VG_(message)(Vg_UserMsg,
317 "Use of uninitialised CPU condition code");
318 } else {
319 VG_(message)(Vg_UserMsg,
320 "Use of uninitialised value of size %d",
321 ec->size);
322 }
323 VG_(pp_ExeContext)(ec->where);
324 break;
325 case AddrErr:
326 switch (ec->axskind) {
327 case ReadAxs:
328 VG_(message)(Vg_UserMsg, "Invalid read of size %d",
329 ec->size );
330 break;
331 case WriteAxs:
332 VG_(message)(Vg_UserMsg, "Invalid write of size %d",
333 ec->size );
334 break;
335 case ExecAxs:
336 VG_(message)(Vg_UserMsg, "Jump to the invalid address "
337 "stated on the next line");
338 break;
339 default:
340 VG_(panic)("pp_ErrContext(axskind)");
341 }
342 VG_(pp_ExeContext)(ec->where);
343 pp_AddrInfo(ec->addr, &ec->addrinfo);
344 break;
345 case FreeErr:
346 VG_(message)(Vg_UserMsg,"Invalid free() / delete / delete[]");
347 /* fall through */
348 case FreeMismatchErr:
349 if (ec->ekind == FreeMismatchErr)
350 VG_(message)(Vg_UserMsg,
351 "Mismatched free() / delete / delete []");
352 VG_(pp_ExeContext)(ec->where);
353 pp_AddrInfo(ec->addr, &ec->addrinfo);
354 break;
355 case ParamErr:
356 if (ec->isWriteableLack) {
357 VG_(message)(Vg_UserMsg,
358 "Syscall param %s contains unaddressable byte(s)",
359 ec->syscall_param );
360 } else {
361 VG_(message)(Vg_UserMsg,
362 "Syscall param %s contains uninitialised or "
363 "unaddressable byte(s)",
364 ec->syscall_param);
365 }
366 VG_(pp_ExeContext)(ec->where);
367 pp_AddrInfo(ec->addr, &ec->addrinfo);
368 break;
369 case UserErr:
370 if (ec->isWriteableLack) {
371 VG_(message)(Vg_UserMsg,
372 "Unaddressable byte(s) found during client check request");
373 } else {
374 VG_(message)(Vg_UserMsg,
375 "Uninitialised or "
376 "unaddressable byte(s) found during client check request");
377 }
378 VG_(pp_ExeContext)(ec->where);
379 pp_AddrInfo(ec->addr, &ec->addrinfo);
380 break;
381 default:
382 VG_(panic)("pp_ErrContext");
383 }
384}
385
386
387/* Figure out if we want to attach for GDB for this error, possibly
388 by asking the user. */
389static
390Bool vg_is_GDB_attach_requested ( void )
391{
392 Char ch, ch2;
393 Int res;
394
395 if (VG_(clo_GDB_attach) == False)
396 return False;
397
398 VG_(message)(Vg_UserMsg, "");
399
400 again:
401 VG_(printf)(
402 "==%d== "
403 "---- Attach to GDB ? --- [Return/N/n/Y/y/C/c] ---- ",
404 VG_(getpid)()
405 );
406
407 res = VG_(read)(0 /*stdin*/, &ch, 1);
408 if (res != 1) goto ioerror;
409 /* res == 1 */
410 if (ch == '\n') return False;
411 if (ch != 'N' && ch != 'n' && ch != 'Y' && ch != 'y'
412 && ch != 'C' && ch != 'c') goto again;
413
414 res = VG_(read)(0 /*stdin*/, &ch2, 1);
415 if (res != 1) goto ioerror;
416 if (ch2 != '\n') goto again;
417
418 /* No, don't want to attach. */
419 if (ch == 'n' || ch == 'N') return False;
420 /* Yes, want to attach. */
421 if (ch == 'y' || ch == 'Y') return True;
422 /* No, don't want to attach, and don't ask again either. */
423 vg_assert(ch == 'c' || ch == 'C');
424
425 ioerror:
426 VG_(clo_GDB_attach) = False;
427 return False;
428}
429
430
431/* Top-level entry point to the error management subsystem. All
432 detected errors are notified here; this routine decides if/when the
433 user should see the error. */
434static void VG_(maybe_add_context) ( ErrContext* ec )
435{
436 ErrContext* p;
437 ErrContext* p_prev;
438 Bool cheap_addr_cmp = False;
439 static Bool is_first_shown_context = True;
440 static Bool stopping_message = False;
441 static Bool slowdown_message = False;
442 static Int vg_n_errs_shown = 0;
443
444 /* After M_VG_COLLECT_NO_ERRORS_AFTER different errors have been
445 found, just refuse to collect any more. */
446 if (vg_n_errs_shown >= M_VG_COLLECT_NO_ERRORS_AFTER) {
447 if (!stopping_message) {
448 VG_(message)(Vg_UserMsg, "");
449 VG_(message)(Vg_UserMsg,
450 "More than %d errors detected. I'm not reporting any more.",
451 M_VG_COLLECT_NO_ERRORS_AFTER);
452 VG_(message)(Vg_UserMsg,
453 "Final error counts may be inaccurate. Go fix your program!");
454 VG_(message)(Vg_UserMsg, "");
455 stopping_message = True;
456 }
457 return;
458 }
459
460 /* After M_VG_COLLECT_ERRORS_SLOWLY_AFTER different errors have
461 been found, be much more conservative about collecting new
462 ones. */
463 if (vg_n_errs_shown >= M_VG_COLLECT_ERRORS_SLOWLY_AFTER) {
464 cheap_addr_cmp = True;
465 if (!slowdown_message) {
466 VG_(message)(Vg_UserMsg, "");
467 VG_(message)(Vg_UserMsg,
468 "More than %d errors detected. Subsequent errors",
469 M_VG_COLLECT_ERRORS_SLOWLY_AFTER);
470 VG_(message)(Vg_UserMsg,
471 "will still be recorded, but in less detail than before.");
472 slowdown_message = True;
473 }
474 }
475
476
477 /* First, see if we've got an error record matching this one. */
478 p = vg_err_contexts;
479 p_prev = NULL;
480 while (p != NULL) {
481 if (eq_ErrContext(cheap_addr_cmp, p, ec)) {
482 /* Found it. */
483 p->count++;
484 if (p->supp != NULL) {
485 /* Deal correctly with suppressed errors. */
486 p->supp->count++;
487 vg_n_errs_suppressed++;
488 } else {
489 vg_n_errs_found++;
490 }
491
492 /* Move p to the front of the list so that future searches
493 for it are faster. */
494 if (p_prev != NULL) {
495 vg_assert(p_prev->next == p);
496 p_prev->next = p->next;
497 p->next = vg_err_contexts;
498 vg_err_contexts = p;
499 }
500 return;
501 }
502 p_prev = p;
503 p = p->next;
504 }
505
506 /* Didn't see it. Copy and add. */
507
508 /* OK, we're really going to collect it. */
509
510 p = VG_(malloc)(VG_AR_ERRCTXT, sizeof(ErrContext));
511 *p = *ec;
512 p->next = vg_err_contexts;
513 p->supp = is_suppressible_error(ec);
514 vg_err_contexts = p;
515 if (p->supp == NULL) {
516 vg_n_errs_found++;
517 if (!is_first_shown_context)
518 VG_(message)(Vg_UserMsg, "");
519 pp_ErrContext(p, False);
520 is_first_shown_context = False;
521 vg_n_errs_shown++;
522 /* Perhaps we want a GDB attach at this point? */
523 if (vg_is_GDB_attach_requested()) {
524 VG_(swizzle_esp_then_start_GDB)();
525 }
526 } else {
527 vg_n_errs_suppressed++;
528 p->supp->count++;
529 }
530}
531
532
533
534
535/*------------------------------------------------------------*/
536/*--- Exported fns ---*/
537/*------------------------------------------------------------*/
538
539void VG_(record_value_error) ( Int size )
540{
541 ErrContext ec;
542 clear_ErrContext( &ec );
543 ec.count = 1;
544 ec.next = NULL;
545 ec.where = VG_(get_ExeContext)( False );
546 ec.ekind = ValueErr;
547 ec.size = size;
548 VG_(maybe_add_context) ( &ec );
549}
550
551void VG_(record_address_error) ( Addr a, Int size, Bool isWrite )
552{
553 ErrContext ec;
554
555 /* If this is caused by an access immediately below %ESP, and the
556 user asks nicely, we just ignore it. */
557 if (VG_(clo_workaround_gcc296_bugs) && VG_(is_just_below_ESP)(a))
558 return;
559
560 clear_ErrContext( &ec );
561 ec.count = 1;
562 ec.next = NULL;
563 ec.where = VG_(get_ExeContext)( False );
564 ec.ekind = AddrErr;
565 ec.axskind = isWrite ? WriteAxs : ReadAxs;
566 ec.size = size;
567 ec.addr = a;
568 VG_(describe_addr) ( a, &ec.addrinfo );
569 VG_(maybe_add_context) ( &ec );
570}
571
572void VG_(record_jump_error) ( Addr a )
573{
574 ErrContext ec;
575 clear_ErrContext( &ec );
576 ec.count = 1;
577 ec.next = NULL;
578 ec.where = VG_(get_ExeContext)( False );
579 ec.ekind = AddrErr;
580 ec.axskind = ExecAxs;
581 ec.addr = a;
582 VG_(describe_addr) ( a, &ec.addrinfo );
583 VG_(maybe_add_context) ( &ec );
584}
585
586void VG_(record_free_error) ( Addr a )
587{
588 ErrContext ec;
589 clear_ErrContext( &ec );
590 ec.count = 1;
591 ec.next = NULL;
592 ec.where = VG_(get_ExeContext)( True );
593 ec.ekind = FreeErr;
594 ec.addr = a;
595 VG_(describe_addr) ( a, &ec.addrinfo );
596 VG_(maybe_add_context) ( &ec );
597}
598
599void VG_(record_freemismatch_error) ( Addr a )
600{
601 ErrContext ec;
602 clear_ErrContext( &ec );
603 ec.count = 1;
604 ec.next = NULL;
605 ec.where = VG_(get_ExeContext)( True );
606 ec.ekind = FreeMismatchErr;
607 ec.addr = a;
608 VG_(describe_addr) ( a, &ec.addrinfo );
609 VG_(maybe_add_context) ( &ec );
610}
611
612void VG_(record_param_err) ( Addr a, Bool isWriteLack, Char* msg )
613{
614 ErrContext ec;
615 clear_ErrContext( &ec );
616 ec.count = 1;
617 ec.next = NULL;
618 ec.where = VG_(get_ExeContext)( False );
619 ec.ekind = ParamErr;
620 ec.addr = a;
621 VG_(describe_addr) ( a, &ec.addrinfo );
622 ec.syscall_param = msg;
623 ec.isWriteableLack = isWriteLack;
624 VG_(maybe_add_context) ( &ec );
625}
626
627
628void VG_(record_user_err) ( Addr a, Bool isWriteLack )
629{
630 ErrContext ec;
631 clear_ErrContext( &ec );
632 ec.count = 1;
633 ec.next = NULL;
634 ec.where = VG_(get_ExeContext)( False );
635 ec.ekind = UserErr;
636 ec.addr = a;
637 VG_(describe_addr) ( a, &ec.addrinfo );
638 ec.isWriteableLack = isWriteLack;
639 VG_(maybe_add_context) ( &ec );
640}
641
642
643void VG_(show_all_errors) ( void )
644{
645 Int i, n_min;
646 Int n_err_contexts, n_supp_contexts;
647 ErrContext *p, *p_min;
648 Suppression *su;
649 Bool any_supp;
650
651 if (VG_(clo_verbosity) == 0)
652 return;
653
654 n_err_contexts = 0;
655 for (p = vg_err_contexts; p != NULL; p = p->next) {
656 if (p->supp == NULL)
657 n_err_contexts++;
658 }
659
660 n_supp_contexts = 0;
661 for (su = vg_suppressions; su != NULL; su = su->next) {
662 if (su->count > 0)
663 n_supp_contexts++;
664 }
665
666 VG_(message)(Vg_UserMsg,
667 "ERROR SUMMARY: "
668 "%d errors from %d contexts (suppressed: %d from %d)",
669 vg_n_errs_found, n_err_contexts,
670 vg_n_errs_suppressed, n_supp_contexts );
671
672 if (VG_(clo_verbosity) <= 1)
673 return;
674
675 /* Print the contexts in order of increasing error count. */
676 for (i = 0; i < n_err_contexts; i++) {
677 n_min = (1 << 30) - 1;
678 p_min = NULL;
679 for (p = vg_err_contexts; p != NULL; p = p->next) {
680 if (p->supp != NULL) continue;
681 if (p->count < n_min) {
682 n_min = p->count;
683 p_min = p;
684 }
685 }
686 if (p_min == NULL) VG_(panic)("pp_AllErrContexts");
687
688 VG_(message)(Vg_UserMsg, "");
689 VG_(message)(Vg_UserMsg, "%d errors in context %d of %d:",
690 p_min->count,
691 i+1, n_err_contexts);
692 pp_ErrContext( p_min, False );
693
694 if ((i+1 == VG_(clo_dump_error))) {
695 VG_(translate) ( p_min->where->eips[0], NULL, NULL, NULL );
696 }
697
698 p_min->count = 1 << 30;
699 }
700
701 if (n_supp_contexts > 0)
702 VG_(message)(Vg_DebugMsg, "");
703 any_supp = False;
704 for (su = vg_suppressions; su != NULL; su = su->next) {
705 if (su->count > 0) {
706 any_supp = True;
707 VG_(message)(Vg_DebugMsg, "supp: %4d %s", su->count,
708 su->sname);
709 }
710 }
711
712 if (n_err_contexts > 0) {
713 if (any_supp)
714 VG_(message)(Vg_UserMsg, "");
715 VG_(message)(Vg_UserMsg,
716 "IN SUMMARY: "
717 "%d errors from %d contexts (suppressed: %d from %d)",
718 vg_n_errs_found, n_err_contexts,
719 vg_n_errs_suppressed,
720 n_supp_contexts );
721 VG_(message)(Vg_UserMsg, "");
722 }
723}
724
725/*------------------------------------------------------------*/
726/*--- Standard suppressions ---*/
727/*------------------------------------------------------------*/
728
729/* Get a non-blank, non-comment line of at most nBuf chars from fd.
730 Skips leading spaces on the line. Return True if EOF was hit instead.
731*/
732
733#define VG_ISSPACE(ch) (((ch)==' ') || ((ch)=='\n') || ((ch)=='\t'))
734
735static Bool getLine ( Int fd, Char* buf, Int nBuf )
736{
737 Char ch;
738 Int n, i;
739 while (True) {
740 /* First, read until a non-blank char appears. */
741 while (True) {
742 n = VG_(read)(fd, &ch, 1);
743 if (n == 1 && !VG_ISSPACE(ch)) break;
744 if (n == 0) return True;
745 }
746
747 /* Now, read the line into buf. */
748 i = 0;
749 buf[i++] = ch; buf[i] = 0;
750 while (True) {
751 n = VG_(read)(fd, &ch, 1);
752 if (n == 0) return False; /* the next call will return True */
753 if (ch == '\n') break;
754 if (i > 0 && i == nBuf-1) i--;
755 buf[i++] = ch; buf[i] = 0;
756 }
757 while (i > 1 && VG_ISSPACE(buf[i-1])) {
758 i--; buf[i] = 0;
759 };
760
761 /* VG_(printf)("The line is `%s'\n", buf); */
762 /* Ok, we have a line. If a non-comment line, return.
763 If a comment line, start all over again. */
764 if (buf[0] != '#') return False;
765 }
766}
767
768
769/* *p_caller contains the raw name of a caller, supposedly either
770 fun:some_function_name or
771 obj:some_object_name.
772 Set *p_ty accordingly and advance *p_caller over the descriptor
773 (fun: or obj:) part.
774 Returns False if failed.
775*/
776static Bool setLocationTy ( Char** p_caller, SuppressionLocTy* p_ty )
777{
778 if (VG_(strncmp)(*p_caller, "fun:", 4) == 0) {
779 (*p_caller) += 4;
780 *p_ty = FunName;
781 return True;
782 }
783 if (VG_(strncmp)(*p_caller, "obj:", 4) == 0) {
784 (*p_caller) += 4;
785 *p_ty = ObjName;
786 return True;
787 }
788 VG_(printf)("location should start with fun: or obj:\n");
789 return False;
790}
791
792
793/* Read suppressions from the file specified in vg_clo_suppressions
794 and place them in the suppressions list. If there's any difficulty
795 doing this, just give up -- there's no point in trying to recover.
796*/
797#define STREQ(s1,s2) (s1 != NULL && s2 != NULL \
798 && VG_(strcmp)((s1),(s2))==0)
799
800static Char* copyStr ( Char* str )
801{
802 Int n, i;
803 Char* str2;
804 n = VG_(strlen)(str);
805 str2 = VG_(malloc)(VG_AR_PRIVATE, n+1);
806 vg_assert(n > 0);
807 for (i = 0; i < n+1; i++) str2[i] = str[i];
808 return str2;
809}
810
811static void load_one_suppressions_file ( Char* filename )
812{
813# define N_BUF 200
814 Int fd;
815 Bool eof;
816 Char buf[N_BUF+1];
817 fd = VG_(open_read)( filename );
818 if (fd == -1) {
819 VG_(message)(Vg_UserMsg,
820 "FATAL: can't open suppressions file `%s'",
821 filename );
822 VG_(exit)(1);
823 }
824
825 while (True) {
826 Suppression* supp;
827 supp = VG_(malloc)(VG_AR_PRIVATE, sizeof(Suppression));
828 supp->count = 0;
829 supp->param = supp->caller0 = supp->caller1
830 = supp->caller2 = supp->caller3 = NULL;
831
832 eof = getLine ( fd, buf, N_BUF );
833 if (eof) break;
834
835 if (!STREQ(buf, "{")) goto syntax_error;
836
837 eof = getLine ( fd, buf, N_BUF );
838 if (eof || STREQ(buf, "}")) goto syntax_error;
839 supp->sname = copyStr(buf);
840
841 eof = getLine ( fd, buf, N_BUF );
842 if (eof) goto syntax_error;
843 else if (STREQ(buf, "Param")) supp->skind = Param;
844 else if (STREQ(buf, "Value0")) supp->skind = Value0;
845 else if (STREQ(buf, "Value1")) supp->skind = Value1;
846 else if (STREQ(buf, "Value2")) supp->skind = Value2;
847 else if (STREQ(buf, "Value4")) supp->skind = Value4;
848 else if (STREQ(buf, "Value8")) supp->skind = Value8;
849 else if (STREQ(buf, "Addr1")) supp->skind = Addr1;
850 else if (STREQ(buf, "Addr2")) supp->skind = Addr2;
851 else if (STREQ(buf, "Addr4")) supp->skind = Addr4;
852 else if (STREQ(buf, "Addr8")) supp->skind = Addr8;
853 else if (STREQ(buf, "Free")) supp->skind = FreeS;
854 else goto syntax_error;
855
856 if (supp->skind == Param) {
857 eof = getLine ( fd, buf, N_BUF );
858 if (eof) goto syntax_error;
859 supp->param = copyStr(buf);
860 }
861
862 eof = getLine ( fd, buf, N_BUF );
863 if (eof) goto syntax_error;
864 supp->caller0 = copyStr(buf);
865 if (!setLocationTy(&(supp->caller0), &(supp->caller0_ty)))
866 goto syntax_error;
867
868 eof = getLine ( fd, buf, N_BUF );
869 if (eof) goto syntax_error;
870 supp->caller1 = copyStr(buf);
871 if (!setLocationTy(&(supp->caller1), &(supp->caller1_ty)))
872 goto syntax_error;
873
874 eof = getLine ( fd, buf, N_BUF );
875 if (eof) goto syntax_error;
876 if (!STREQ(buf, "}")) {
877 supp->caller2 = copyStr(buf);
878 if (!setLocationTy(&(supp->caller2), &(supp->caller2_ty)))
879 goto syntax_error;
880 eof = getLine ( fd, buf, N_BUF );
881 if (eof) goto syntax_error;
882 if (!STREQ(buf, "}")) {
883 supp->caller3 = copyStr(buf);
884 if (!setLocationTy(&(supp->caller3), &(supp->caller3_ty)))
885 goto syntax_error;
886 eof = getLine ( fd, buf, N_BUF );
887 if (eof || !STREQ(buf, "}")) goto syntax_error;
888 }
889 }
890
891 supp->next = vg_suppressions;
892 vg_suppressions = supp;
893 }
894
895 VG_(close)(fd);
896 return;
897
898 syntax_error:
899 if (eof) {
900 VG_(message)(Vg_UserMsg,
901 "FATAL: in suppressions file `%s': unexpected EOF",
902 filename );
903 } else {
904 VG_(message)(Vg_UserMsg,
905 "FATAL: in suppressions file `%s': syntax error on: %s",
906 filename, buf );
907 }
908 VG_(close)(fd);
909 VG_(message)(Vg_UserMsg, "exiting now.");
910 VG_(exit)(1);
911
912# undef N_BUF
913}
914
915
916void VG_(load_suppressions) ( void )
917{
918 Int i;
919 vg_suppressions = NULL;
920 for (i = 0; i < VG_(clo_n_suppressions); i++) {
921 if (VG_(clo_verbosity) > 1) {
922 VG_(message)(Vg_UserMsg, "Reading suppressions file: %s",
923 VG_(clo_suppressions)[i] );
924 }
925 load_one_suppressions_file( VG_(clo_suppressions)[i] );
926 }
927}
928
929
930/* Does an error context match a suppression? ie is this a
931 suppressible error? If so, return a pointer to the Suppression
932 record, otherwise NULL.
933 Tries to minimise the number of calls to what_fn_is_this since they
934 are expensive.
935*/
936static Suppression* is_suppressible_error ( ErrContext* ec )
937{
938# define STREQ(s1,s2) (s1 != NULL && s2 != NULL \
939 && VG_(strcmp)((s1),(s2))==0)
940
941 Char caller0_obj[M_VG_ERRTXT];
942 Char caller0_fun[M_VG_ERRTXT];
943 Char caller1_obj[M_VG_ERRTXT];
944 Char caller1_fun[M_VG_ERRTXT];
945 Char caller2_obj[M_VG_ERRTXT];
946 Char caller2_fun[M_VG_ERRTXT];
947 Char caller3_obj[M_VG_ERRTXT];
948 Char caller3_fun[M_VG_ERRTXT];
949
950 Suppression* su;
951 Int su_size;
952
953 /* vg_what_fn_or_object_is_this returns:
954 <function_name> or
955 <object_name> or
956 ???
957 so the strings in the suppression file should match these.
958 */
959
960 /* Initialise these strs so they are always safe to compare, even
961 if what_fn_or_object_is_this doesn't write anything to them. */
962 caller0_obj[0] = caller1_obj[0] = caller2_obj[0] = caller3_obj[0] = 0;
963 caller0_fun[0] = caller1_fun[0] = caller2_obj[0] = caller3_obj[0] = 0;
964
965 VG_(what_obj_and_fun_is_this)
966 ( ec->where->eips[0], caller0_obj, M_VG_ERRTXT,
967 caller0_fun, M_VG_ERRTXT );
968 VG_(what_obj_and_fun_is_this)
969 ( ec->where->eips[1], caller1_obj, M_VG_ERRTXT,
970 caller1_fun, M_VG_ERRTXT );
971
972 if (VG_(clo_backtrace_size) > 2) {
973 VG_(what_obj_and_fun_is_this)
974 ( ec->where->eips[2], caller2_obj, M_VG_ERRTXT,
975 caller2_fun, M_VG_ERRTXT );
976
977 if (VG_(clo_backtrace_size) > 3) {
978 VG_(what_obj_and_fun_is_this)
979 ( ec->where->eips[3], caller3_obj, M_VG_ERRTXT,
980 caller3_fun, M_VG_ERRTXT );
981 }
982 }
983
984 /* See if the error context matches any suppression. */
985 for (su = vg_suppressions; su != NULL; su = su->next) {
986 switch (su->skind) {
987 case FreeS:
988 case Param: case Value0: su_size = 0; break;
989 case Value1: case Addr1: su_size = 1; break;
990 case Value2: case Addr2: su_size = 2; break;
991 case Value4: case Addr4: su_size = 4; break;
992 case Value8: case Addr8: su_size = 8; break;
993 default: VG_(panic)("errcontext_matches_suppression");
994 }
995 switch (su->skind) {
996 case Param:
997 if (ec->ekind != ParamErr) continue;
998 if (!STREQ(su->param, ec->syscall_param)) continue;
999 break;
1000 case Value0: case Value1: case Value2: case Value4: case Value8:
1001 if (ec->ekind != ValueErr) continue;
1002 if (ec->size != su_size) continue;
1003 break;
1004 case Addr1: case Addr2: case Addr4: case Addr8:
1005 if (ec->ekind != AddrErr) continue;
1006 if (ec->size != su_size) continue;
1007 break;
1008 case FreeS:
1009 if (ec->ekind != FreeErr && ec->ekind != FreeMismatchErr) continue;
1010 break;
1011 }
1012
1013 switch (su->caller0_ty) {
1014 case ObjName: if (!VG_(stringMatch)(su->caller0,
1015 caller0_obj)) continue;
1016 break;
1017 case FunName: if (!VG_(stringMatch)(su->caller0,
1018 caller0_fun)) continue;
1019 break;
1020 default: goto baaaad;
1021 }
1022
1023 switch (su->caller1_ty) {
1024 case ObjName: if (!VG_(stringMatch)(su->caller1,
1025 caller1_obj)) continue;
1026 break;
1027 case FunName: if (!VG_(stringMatch)(su->caller1,
1028 caller1_fun)) continue;
1029 break;
1030 default: goto baaaad;
1031 }
1032
1033 if (VG_(clo_backtrace_size) > 2 && su->caller2 != NULL) {
1034 switch (su->caller2_ty) {
1035 case ObjName: if (!VG_(stringMatch)(su->caller2,
1036 caller2_obj)) continue;
1037 break;
1038 case FunName: if (!VG_(stringMatch)(su->caller2,
1039 caller2_fun)) continue;
1040 break;
1041 default: goto baaaad;
1042 }
1043 }
1044
1045 if (VG_(clo_backtrace_size) > 3 && su->caller3 != NULL) {
1046 switch (su->caller3_ty) {
1047 case ObjName: if (!VG_(stringMatch)(su->caller3,
1048 caller3_obj)) continue;
1049 break;
1050 case FunName: if (!VG_(stringMatch)(su->caller3,
1051 caller3_fun)) continue;
1052 break;
1053 default: goto baaaad;
1054 }
1055 }
1056
1057 return su;
1058 }
1059
1060 return NULL;
1061
1062 baaaad:
1063 VG_(panic)("is_suppressible_error");
1064
1065# undef STREQ
1066}
1067
1068/*--------------------------------------------------------------------*/
1069/*--- end vg_errcontext.c ---*/
1070/*--------------------------------------------------------------------*/