blob: 0ac2cb36b4855d1d5fc5325bba41f0fe4b053ad8 [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;
sewardjde4a1d02002-03-22 01:27:54 +0000147 }
148 ErrContext;
149
150/* The list of error contexts found, both suppressed and unsuppressed.
151 Initially empty, and grows as errors are detected. */
152static ErrContext* vg_err_contexts = NULL;
153
154/* The list of suppression directives, as read from the specified
155 suppressions file. */
156static Suppression* vg_suppressions = NULL;
157
158/* Running count of unsuppressed errors detected. */
159static UInt vg_n_errs_found = 0;
160
161/* Running count of suppressed errors detected. */
162static UInt vg_n_errs_suppressed = 0;
163
164/* forwards ... */
165static Suppression* is_suppressible_error ( ErrContext* ec );
166
167
168/*------------------------------------------------------------*/
169/*--- Helper fns ---*/
170/*------------------------------------------------------------*/
171
172
173static void clear_AddrInfo ( AddrInfo* ai )
174{
175 ai->akind = Unknown;
176 ai->blksize = 0;
177 ai->rwoffset = 0;
178 ai->lastchange = NULL;
sewardj1e8cdc92002-04-18 11:37:52 +0000179 ai->stack_tid = VG_INVALID_THREADID;
sewardjde4a1d02002-03-22 01:27:54 +0000180}
181
182static void clear_ErrContext ( ErrContext* ec )
183{
184 ec->next = NULL;
185 ec->supp = NULL;
186 ec->count = 0;
187 ec->ekind = ValueErr;
188 ec->where = NULL;
189 ec->axskind = ReadAxs;
190 ec->size = 0;
191 ec->addr = 0;
192 clear_AddrInfo ( &ec->addrinfo );
193 ec->syscall_param = NULL;
194 ec->isWriteableLack = False;
sewardj1e8cdc92002-04-18 11:37:52 +0000195 ec->tid = VG_INVALID_THREADID;
sewardjde4a1d02002-03-22 01:27:54 +0000196}
197
198
199static __inline__
200Bool vg_eq_ExeContext ( Bool top_2_only,
201 ExeContext* e1, ExeContext* e2 )
202{
203 /* Note that frames after the 4th are always ignored. */
204 if (top_2_only) {
205 return VG_(eq_ExeContext_top2(e1, e2));
206 } else {
207 return VG_(eq_ExeContext_top4(e1, e2));
208 }
209}
210
211
212static Bool eq_AddrInfo ( Bool cheap_addr_cmp,
213 AddrInfo* ai1, AddrInfo* ai2 )
214{
215 if (ai1->akind != ai2->akind)
216 return False;
217 if (ai1->akind == Freed || ai1->akind == Mallocd) {
218 if (ai1->blksize != ai2->blksize)
219 return False;
220 if (!vg_eq_ExeContext(cheap_addr_cmp,
221 ai1->lastchange, ai2->lastchange))
222 return False;
223 }
224 return True;
225}
226
227/* Compare error contexts, to detect duplicates. Note that if they
228 are otherwise the same, the faulting addrs and associated rwoffsets
229 are allowed to be different. */
230
231static Bool eq_ErrContext ( Bool cheap_addr_cmp,
232 ErrContext* e1, ErrContext* e2 )
233{
234 if (e1->ekind != e2->ekind)
235 return False;
236 if (!vg_eq_ExeContext(cheap_addr_cmp, e1->where, e2->where))
237 return False;
238
239 switch (e1->ekind) {
240 case UserErr:
241 case ParamErr:
242 if (e1->isWriteableLack != e2->isWriteableLack) return False;
243 if (e1->ekind == ParamErr
244 && 0 != VG_(strcmp)(e1->syscall_param, e2->syscall_param))
245 return False;
246 return True;
247 case FreeErr:
248 case FreeMismatchErr:
249 if (e1->addr != e2->addr) return False;
250 if (!eq_AddrInfo(cheap_addr_cmp, &e1->addrinfo, &e2->addrinfo))
251 return False;
252 return True;
253 case AddrErr:
254 if (e1->axskind != e2->axskind) return False;
255 if (e1->size != e2->size) return False;
256 if (!eq_AddrInfo(cheap_addr_cmp, &e1->addrinfo, &e2->addrinfo))
257 return False;
258 return True;
259 case ValueErr:
260 if (e1->size != e2->size) return False;
261 return True;
262 default:
263 VG_(panic)("eq_ErrContext");
264 }
265}
266
267static void pp_AddrInfo ( Addr a, AddrInfo* ai )
268{
269 switch (ai->akind) {
270 case Stack:
sewardj1e8cdc92002-04-18 11:37:52 +0000271 VG_(message)(Vg_UserMsg,
272 " Address 0x%x is on thread %d's stack",
273 ai->stack_tid, a);
sewardjde4a1d02002-03-22 01:27:54 +0000274 break;
275 case Unknown:
276 VG_(message)(Vg_UserMsg,
277 " Address 0x%x is not stack'd, malloc'd or free'd", a);
278 break;
279 case Freed: case Mallocd: case UserG: case UserS: {
280 UInt delta;
281 UChar* relative;
282 if (ai->rwoffset < 0) {
283 delta = (UInt)(- ai->rwoffset);
284 relative = "before";
285 } else if (ai->rwoffset >= ai->blksize) {
286 delta = ai->rwoffset - ai->blksize;
287 relative = "after";
288 } else {
289 delta = ai->rwoffset;
290 relative = "inside";
291 }
292 if (ai->akind == UserS) {
293 VG_(message)(Vg_UserMsg,
294 " Address 0x%x is %d bytes %s a %d-byte stack red-zone created",
295 a, delta, relative,
296 ai->blksize );
297 } else {
298 VG_(message)(Vg_UserMsg,
299 " Address 0x%x is %d bytes %s a block of size %d %s",
300 a, delta, relative,
301 ai->blksize,
302 ai->akind==Mallocd ? "alloc'd"
303 : ai->akind==Freed ? "free'd"
304 : "client-defined");
305 }
306 VG_(pp_ExeContext)(ai->lastchange);
307 break;
308 }
309 default:
310 VG_(panic)("pp_AddrInfo");
311 }
312}
313
314static void pp_ErrContext ( ErrContext* ec, Bool printCount )
315{
316 if (printCount)
317 VG_(message)(Vg_UserMsg, "Observed %d times:", ec->count );
sewardj1e8cdc92002-04-18 11:37:52 +0000318 if (ec->tid > 0)
319 VG_(message)(Vg_UserMsg, "Thread %d:", ec->tid );
sewardjde4a1d02002-03-22 01:27:54 +0000320 switch (ec->ekind) {
321 case ValueErr:
322 if (ec->size == 0) {
sewardja7dc7952002-03-24 11:29:13 +0000323 VG_(message)(
324 Vg_UserMsg,
325 "Conditional jump or move depends on uninitialised value(s)");
sewardjde4a1d02002-03-22 01:27:54 +0000326 } else {
327 VG_(message)(Vg_UserMsg,
328 "Use of uninitialised value of size %d",
329 ec->size);
330 }
331 VG_(pp_ExeContext)(ec->where);
332 break;
333 case AddrErr:
334 switch (ec->axskind) {
335 case ReadAxs:
336 VG_(message)(Vg_UserMsg, "Invalid read of size %d",
337 ec->size );
338 break;
339 case WriteAxs:
340 VG_(message)(Vg_UserMsg, "Invalid write of size %d",
341 ec->size );
342 break;
343 case ExecAxs:
344 VG_(message)(Vg_UserMsg, "Jump to the invalid address "
345 "stated on the next line");
346 break;
347 default:
348 VG_(panic)("pp_ErrContext(axskind)");
349 }
350 VG_(pp_ExeContext)(ec->where);
351 pp_AddrInfo(ec->addr, &ec->addrinfo);
352 break;
353 case FreeErr:
354 VG_(message)(Vg_UserMsg,"Invalid free() / delete / delete[]");
355 /* fall through */
356 case FreeMismatchErr:
357 if (ec->ekind == FreeMismatchErr)
358 VG_(message)(Vg_UserMsg,
359 "Mismatched free() / delete / delete []");
360 VG_(pp_ExeContext)(ec->where);
361 pp_AddrInfo(ec->addr, &ec->addrinfo);
362 break;
363 case ParamErr:
364 if (ec->isWriteableLack) {
365 VG_(message)(Vg_UserMsg,
366 "Syscall param %s contains unaddressable byte(s)",
367 ec->syscall_param );
368 } else {
369 VG_(message)(Vg_UserMsg,
370 "Syscall param %s contains uninitialised or "
371 "unaddressable byte(s)",
372 ec->syscall_param);
373 }
374 VG_(pp_ExeContext)(ec->where);
375 pp_AddrInfo(ec->addr, &ec->addrinfo);
376 break;
377 case UserErr:
378 if (ec->isWriteableLack) {
379 VG_(message)(Vg_UserMsg,
380 "Unaddressable byte(s) found during client check request");
381 } else {
382 VG_(message)(Vg_UserMsg,
383 "Uninitialised or "
384 "unaddressable byte(s) found during client check request");
385 }
386 VG_(pp_ExeContext)(ec->where);
387 pp_AddrInfo(ec->addr, &ec->addrinfo);
388 break;
389 default:
390 VG_(panic)("pp_ErrContext");
391 }
392}
393
394
395/* Figure out if we want to attach for GDB for this error, possibly
396 by asking the user. */
397static
398Bool vg_is_GDB_attach_requested ( void )
399{
400 Char ch, ch2;
401 Int res;
402
403 if (VG_(clo_GDB_attach) == False)
404 return False;
405
406 VG_(message)(Vg_UserMsg, "");
407
408 again:
409 VG_(printf)(
410 "==%d== "
411 "---- Attach to GDB ? --- [Return/N/n/Y/y/C/c] ---- ",
412 VG_(getpid)()
413 );
414
415 res = VG_(read)(0 /*stdin*/, &ch, 1);
416 if (res != 1) goto ioerror;
417 /* res == 1 */
418 if (ch == '\n') return False;
419 if (ch != 'N' && ch != 'n' && ch != 'Y' && ch != 'y'
420 && ch != 'C' && ch != 'c') goto again;
421
422 res = VG_(read)(0 /*stdin*/, &ch2, 1);
423 if (res != 1) goto ioerror;
424 if (ch2 != '\n') goto again;
425
426 /* No, don't want to attach. */
427 if (ch == 'n' || ch == 'N') return False;
428 /* Yes, want to attach. */
429 if (ch == 'y' || ch == 'Y') return True;
430 /* No, don't want to attach, and don't ask again either. */
431 vg_assert(ch == 'c' || ch == 'C');
432
433 ioerror:
434 VG_(clo_GDB_attach) = False;
435 return False;
436}
437
438
439/* Top-level entry point to the error management subsystem. All
440 detected errors are notified here; this routine decides if/when the
441 user should see the error. */
442static void VG_(maybe_add_context) ( ErrContext* ec )
443{
444 ErrContext* p;
445 ErrContext* p_prev;
446 Bool cheap_addr_cmp = False;
447 static Bool is_first_shown_context = True;
448 static Bool stopping_message = False;
449 static Bool slowdown_message = False;
450 static Int vg_n_errs_shown = 0;
451
sewardj1e8cdc92002-04-18 11:37:52 +0000452 vg_assert(ec->tid >= 0 && ec->tid < VG_N_THREADS);
453
sewardjde4a1d02002-03-22 01:27:54 +0000454 /* After M_VG_COLLECT_NO_ERRORS_AFTER different errors have been
455 found, just refuse to collect any more. */
456 if (vg_n_errs_shown >= M_VG_COLLECT_NO_ERRORS_AFTER) {
457 if (!stopping_message) {
458 VG_(message)(Vg_UserMsg, "");
459 VG_(message)(Vg_UserMsg,
460 "More than %d errors detected. I'm not reporting any more.",
461 M_VG_COLLECT_NO_ERRORS_AFTER);
462 VG_(message)(Vg_UserMsg,
463 "Final error counts may be inaccurate. Go fix your program!");
464 VG_(message)(Vg_UserMsg, "");
465 stopping_message = True;
466 }
467 return;
468 }
469
470 /* After M_VG_COLLECT_ERRORS_SLOWLY_AFTER different errors have
471 been found, be much more conservative about collecting new
472 ones. */
473 if (vg_n_errs_shown >= M_VG_COLLECT_ERRORS_SLOWLY_AFTER) {
474 cheap_addr_cmp = True;
475 if (!slowdown_message) {
476 VG_(message)(Vg_UserMsg, "");
477 VG_(message)(Vg_UserMsg,
478 "More than %d errors detected. Subsequent errors",
479 M_VG_COLLECT_ERRORS_SLOWLY_AFTER);
480 VG_(message)(Vg_UserMsg,
481 "will still be recorded, but in less detail than before.");
482 slowdown_message = True;
483 }
484 }
485
486
487 /* First, see if we've got an error record matching this one. */
488 p = vg_err_contexts;
489 p_prev = NULL;
490 while (p != NULL) {
491 if (eq_ErrContext(cheap_addr_cmp, p, ec)) {
492 /* Found it. */
493 p->count++;
494 if (p->supp != NULL) {
495 /* Deal correctly with suppressed errors. */
496 p->supp->count++;
497 vg_n_errs_suppressed++;
498 } else {
499 vg_n_errs_found++;
500 }
501
502 /* Move p to the front of the list so that future searches
503 for it are faster. */
504 if (p_prev != NULL) {
505 vg_assert(p_prev->next == p);
506 p_prev->next = p->next;
507 p->next = vg_err_contexts;
508 vg_err_contexts = p;
509 }
510 return;
511 }
512 p_prev = p;
513 p = p->next;
514 }
515
516 /* Didn't see it. Copy and add. */
517
518 /* OK, we're really going to collect it. */
519
520 p = VG_(malloc)(VG_AR_ERRCTXT, sizeof(ErrContext));
521 *p = *ec;
522 p->next = vg_err_contexts;
523 p->supp = is_suppressible_error(ec);
524 vg_err_contexts = p;
525 if (p->supp == NULL) {
526 vg_n_errs_found++;
527 if (!is_first_shown_context)
528 VG_(message)(Vg_UserMsg, "");
529 pp_ErrContext(p, False);
530 is_first_shown_context = False;
531 vg_n_errs_shown++;
532 /* Perhaps we want a GDB attach at this point? */
533 if (vg_is_GDB_attach_requested()) {
534 VG_(swizzle_esp_then_start_GDB)();
535 }
536 } else {
537 vg_n_errs_suppressed++;
538 p->supp->count++;
539 }
540}
541
542
543
544
545/*------------------------------------------------------------*/
546/*--- Exported fns ---*/
547/*------------------------------------------------------------*/
548
sewardj8c824512002-04-14 04:16:48 +0000549/* These are all called from generated code, so that the %EIP/%EBP
550 values that we need in order to create proper error messages are
551 picked up out of VG_(baseBlock) rather than from the thread table
552 (vg_threads in vg_scheduler.c). */
553
sewardjde4a1d02002-03-22 01:27:54 +0000554void VG_(record_value_error) ( Int size )
555{
556 ErrContext ec;
557 clear_ErrContext( &ec );
558 ec.count = 1;
559 ec.next = NULL;
sewardj8c824512002-04-14 04:16:48 +0000560 ec.where = VG_(get_ExeContext)( False, VG_(baseBlock)[VGOFF_(m_eip)],
561 VG_(baseBlock)[VGOFF_(m_ebp)] );
sewardjde4a1d02002-03-22 01:27:54 +0000562 ec.ekind = ValueErr;
563 ec.size = size;
sewardj1e8cdc92002-04-18 11:37:52 +0000564 ec.tid = VG_(get_current_tid)();
sewardjde4a1d02002-03-22 01:27:54 +0000565 VG_(maybe_add_context) ( &ec );
566}
567
568void VG_(record_address_error) ( Addr a, Int size, Bool isWrite )
569{
570 ErrContext ec;
571
572 /* If this is caused by an access immediately below %ESP, and the
573 user asks nicely, we just ignore it. */
sewardj8c824512002-04-14 04:16:48 +0000574 if (VG_(clo_workaround_gcc296_bugs)
575 && VG_(is_just_below_ESP)( VG_(baseBlock)[VGOFF_(m_esp)], a ))
sewardjde4a1d02002-03-22 01:27:54 +0000576 return;
577
578 clear_ErrContext( &ec );
579 ec.count = 1;
580 ec.next = NULL;
sewardj8c824512002-04-14 04:16:48 +0000581 ec.where = VG_(get_ExeContext)( False, VG_(baseBlock)[VGOFF_(m_eip)],
582 VG_(baseBlock)[VGOFF_(m_ebp)] );
sewardjde4a1d02002-03-22 01:27:54 +0000583 ec.ekind = AddrErr;
584 ec.axskind = isWrite ? WriteAxs : ReadAxs;
585 ec.size = size;
586 ec.addr = a;
sewardj1e8cdc92002-04-18 11:37:52 +0000587 ec.tid = VG_(get_current_tid)();
sewardjde4a1d02002-03-22 01:27:54 +0000588 VG_(describe_addr) ( a, &ec.addrinfo );
589 VG_(maybe_add_context) ( &ec );
590}
591
592void VG_(record_free_error) ( Addr a )
593{
594 ErrContext ec;
595 clear_ErrContext( &ec );
596 ec.count = 1;
597 ec.next = NULL;
sewardj8c824512002-04-14 04:16:48 +0000598 ec.where = VG_(get_ExeContext)( True, VG_(baseBlock)[VGOFF_(m_eip)],
599 VG_(baseBlock)[VGOFF_(m_ebp)] );
sewardjde4a1d02002-03-22 01:27:54 +0000600 ec.ekind = FreeErr;
601 ec.addr = a;
sewardj1e8cdc92002-04-18 11:37:52 +0000602 ec.tid = VG_(get_current_tid)();
sewardjde4a1d02002-03-22 01:27:54 +0000603 VG_(describe_addr) ( a, &ec.addrinfo );
604 VG_(maybe_add_context) ( &ec );
605}
606
607void VG_(record_freemismatch_error) ( Addr a )
608{
609 ErrContext ec;
610 clear_ErrContext( &ec );
611 ec.count = 1;
612 ec.next = NULL;
sewardj8c824512002-04-14 04:16:48 +0000613 ec.where = VG_(get_ExeContext)( True, VG_(baseBlock)[VGOFF_(m_eip)],
614 VG_(baseBlock)[VGOFF_(m_ebp)] );
sewardjde4a1d02002-03-22 01:27:54 +0000615 ec.ekind = FreeMismatchErr;
616 ec.addr = a;
sewardj1e8cdc92002-04-18 11:37:52 +0000617 ec.tid = VG_(get_current_tid)();
sewardjde4a1d02002-03-22 01:27:54 +0000618 VG_(describe_addr) ( a, &ec.addrinfo );
619 VG_(maybe_add_context) ( &ec );
620}
621
sewardj1e8cdc92002-04-18 11:37:52 +0000622
623/* These three are called not from generated code but in response to
sewardj8c824512002-04-14 04:16:48 +0000624 requests passed back to the scheduler. So we pick up %EIP/%EBP
625 values from the stored thread state, not from VG_(baseBlock). */
626
sewardj1e8cdc92002-04-18 11:37:52 +0000627void VG_(record_jump_error) ( ThreadState* tst, Addr a )
628{
629 ErrContext ec;
630 clear_ErrContext( &ec );
631 ec.count = 1;
632 ec.next = NULL;
633 ec.where = VG_(get_ExeContext)( False, tst->m_eip, tst->m_ebp );
634 ec.ekind = AddrErr;
635 ec.axskind = ExecAxs;
636 ec.addr = a;
637 ec.tid = tst->tid;
638 VG_(describe_addr) ( a, &ec.addrinfo );
639 VG_(maybe_add_context) ( &ec );
640}
641
sewardj8c824512002-04-14 04:16:48 +0000642void VG_(record_param_err) ( ThreadState* tst, Addr a, Bool isWriteLack,
643 Char* msg )
sewardjde4a1d02002-03-22 01:27:54 +0000644{
645 ErrContext ec;
646 clear_ErrContext( &ec );
647 ec.count = 1;
648 ec.next = NULL;
sewardj8c824512002-04-14 04:16:48 +0000649 ec.where = VG_(get_ExeContext)( False, tst->m_eip, tst->m_ebp );
sewardjde4a1d02002-03-22 01:27:54 +0000650 ec.ekind = ParamErr;
651 ec.addr = a;
sewardj1e8cdc92002-04-18 11:37:52 +0000652 ec.tid = tst->tid;
sewardjde4a1d02002-03-22 01:27:54 +0000653 VG_(describe_addr) ( a, &ec.addrinfo );
654 ec.syscall_param = msg;
655 ec.isWriteableLack = isWriteLack;
656 VG_(maybe_add_context) ( &ec );
657}
658
sewardj8c824512002-04-14 04:16:48 +0000659void VG_(record_user_err) ( ThreadState* tst, Addr a, Bool isWriteLack )
sewardjde4a1d02002-03-22 01:27:54 +0000660{
661 ErrContext ec;
662 clear_ErrContext( &ec );
663 ec.count = 1;
664 ec.next = NULL;
sewardj8c824512002-04-14 04:16:48 +0000665 ec.where = VG_(get_ExeContext)( False, tst->m_eip, tst->m_ebp );
sewardjde4a1d02002-03-22 01:27:54 +0000666 ec.ekind = UserErr;
667 ec.addr = a;
sewardj1e8cdc92002-04-18 11:37:52 +0000668 ec.tid = tst->tid;
sewardjde4a1d02002-03-22 01:27:54 +0000669 VG_(describe_addr) ( a, &ec.addrinfo );
670 ec.isWriteableLack = isWriteLack;
671 VG_(maybe_add_context) ( &ec );
672}
673
674
sewardj8c824512002-04-14 04:16:48 +0000675/*------------------------------*/
676
sewardjde4a1d02002-03-22 01:27:54 +0000677void VG_(show_all_errors) ( void )
678{
679 Int i, n_min;
680 Int n_err_contexts, n_supp_contexts;
681 ErrContext *p, *p_min;
682 Suppression *su;
683 Bool any_supp;
684
685 if (VG_(clo_verbosity) == 0)
686 return;
687
688 n_err_contexts = 0;
689 for (p = vg_err_contexts; p != NULL; p = p->next) {
690 if (p->supp == NULL)
691 n_err_contexts++;
692 }
693
694 n_supp_contexts = 0;
695 for (su = vg_suppressions; su != NULL; su = su->next) {
696 if (su->count > 0)
697 n_supp_contexts++;
698 }
699
700 VG_(message)(Vg_UserMsg,
701 "ERROR SUMMARY: "
702 "%d errors from %d contexts (suppressed: %d from %d)",
703 vg_n_errs_found, n_err_contexts,
704 vg_n_errs_suppressed, n_supp_contexts );
705
706 if (VG_(clo_verbosity) <= 1)
707 return;
708
709 /* Print the contexts in order of increasing error count. */
710 for (i = 0; i < n_err_contexts; i++) {
711 n_min = (1 << 30) - 1;
712 p_min = NULL;
713 for (p = vg_err_contexts; p != NULL; p = p->next) {
714 if (p->supp != NULL) continue;
715 if (p->count < n_min) {
716 n_min = p->count;
717 p_min = p;
718 }
719 }
720 if (p_min == NULL) VG_(panic)("pp_AllErrContexts");
721
722 VG_(message)(Vg_UserMsg, "");
723 VG_(message)(Vg_UserMsg, "%d errors in context %d of %d:",
724 p_min->count,
725 i+1, n_err_contexts);
726 pp_ErrContext( p_min, False );
727
728 if ((i+1 == VG_(clo_dump_error))) {
sewardj1e8cdc92002-04-18 11:37:52 +0000729 VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to below NULLs */,
730 p_min->where->eips[0], NULL, NULL, NULL );
sewardjde4a1d02002-03-22 01:27:54 +0000731 }
732
733 p_min->count = 1 << 30;
734 }
735
736 if (n_supp_contexts > 0)
737 VG_(message)(Vg_DebugMsg, "");
738 any_supp = False;
739 for (su = vg_suppressions; su != NULL; su = su->next) {
740 if (su->count > 0) {
741 any_supp = True;
742 VG_(message)(Vg_DebugMsg, "supp: %4d %s", su->count,
743 su->sname);
744 }
745 }
746
747 if (n_err_contexts > 0) {
748 if (any_supp)
749 VG_(message)(Vg_UserMsg, "");
750 VG_(message)(Vg_UserMsg,
751 "IN SUMMARY: "
752 "%d errors from %d contexts (suppressed: %d from %d)",
753 vg_n_errs_found, n_err_contexts,
754 vg_n_errs_suppressed,
755 n_supp_contexts );
756 VG_(message)(Vg_UserMsg, "");
757 }
758}
759
760/*------------------------------------------------------------*/
761/*--- Standard suppressions ---*/
762/*------------------------------------------------------------*/
763
764/* Get a non-blank, non-comment line of at most nBuf chars from fd.
765 Skips leading spaces on the line. Return True if EOF was hit instead.
766*/
767
768#define VG_ISSPACE(ch) (((ch)==' ') || ((ch)=='\n') || ((ch)=='\t'))
769
770static Bool getLine ( Int fd, Char* buf, Int nBuf )
771{
772 Char ch;
773 Int n, i;
774 while (True) {
775 /* First, read until a non-blank char appears. */
776 while (True) {
777 n = VG_(read)(fd, &ch, 1);
778 if (n == 1 && !VG_ISSPACE(ch)) break;
779 if (n == 0) return True;
780 }
781
782 /* Now, read the line into buf. */
783 i = 0;
784 buf[i++] = ch; buf[i] = 0;
785 while (True) {
786 n = VG_(read)(fd, &ch, 1);
787 if (n == 0) return False; /* the next call will return True */
788 if (ch == '\n') break;
789 if (i > 0 && i == nBuf-1) i--;
790 buf[i++] = ch; buf[i] = 0;
791 }
792 while (i > 1 && VG_ISSPACE(buf[i-1])) {
793 i--; buf[i] = 0;
794 };
795
796 /* VG_(printf)("The line is `%s'\n", buf); */
797 /* Ok, we have a line. If a non-comment line, return.
798 If a comment line, start all over again. */
799 if (buf[0] != '#') return False;
800 }
801}
802
803
804/* *p_caller contains the raw name of a caller, supposedly either
805 fun:some_function_name or
806 obj:some_object_name.
807 Set *p_ty accordingly and advance *p_caller over the descriptor
808 (fun: or obj:) part.
809 Returns False if failed.
810*/
811static Bool setLocationTy ( Char** p_caller, SuppressionLocTy* p_ty )
812{
813 if (VG_(strncmp)(*p_caller, "fun:", 4) == 0) {
814 (*p_caller) += 4;
815 *p_ty = FunName;
816 return True;
817 }
818 if (VG_(strncmp)(*p_caller, "obj:", 4) == 0) {
819 (*p_caller) += 4;
820 *p_ty = ObjName;
821 return True;
822 }
823 VG_(printf)("location should start with fun: or obj:\n");
824 return False;
825}
826
827
828/* Read suppressions from the file specified in vg_clo_suppressions
829 and place them in the suppressions list. If there's any difficulty
830 doing this, just give up -- there's no point in trying to recover.
831*/
832#define STREQ(s1,s2) (s1 != NULL && s2 != NULL \
833 && VG_(strcmp)((s1),(s2))==0)
834
835static Char* copyStr ( Char* str )
836{
837 Int n, i;
838 Char* str2;
839 n = VG_(strlen)(str);
840 str2 = VG_(malloc)(VG_AR_PRIVATE, n+1);
841 vg_assert(n > 0);
842 for (i = 0; i < n+1; i++) str2[i] = str[i];
843 return str2;
844}
845
846static void load_one_suppressions_file ( Char* filename )
847{
848# define N_BUF 200
849 Int fd;
850 Bool eof;
851 Char buf[N_BUF+1];
852 fd = VG_(open_read)( filename );
853 if (fd == -1) {
854 VG_(message)(Vg_UserMsg,
855 "FATAL: can't open suppressions file `%s'",
856 filename );
857 VG_(exit)(1);
858 }
859
860 while (True) {
861 Suppression* supp;
862 supp = VG_(malloc)(VG_AR_PRIVATE, sizeof(Suppression));
863 supp->count = 0;
864 supp->param = supp->caller0 = supp->caller1
865 = supp->caller2 = supp->caller3 = NULL;
866
867 eof = getLine ( fd, buf, N_BUF );
868 if (eof) break;
869
870 if (!STREQ(buf, "{")) goto syntax_error;
871
872 eof = getLine ( fd, buf, N_BUF );
873 if (eof || STREQ(buf, "}")) goto syntax_error;
874 supp->sname = copyStr(buf);
875
876 eof = getLine ( fd, buf, N_BUF );
877 if (eof) goto syntax_error;
878 else if (STREQ(buf, "Param")) supp->skind = Param;
sewardja7dc7952002-03-24 11:29:13 +0000879 else if (STREQ(buf, "Value0")) supp->skind = Value0; /* backwards compat */
880 else if (STREQ(buf, "Cond")) supp->skind = Value0;
sewardjde4a1d02002-03-22 01:27:54 +0000881 else if (STREQ(buf, "Value1")) supp->skind = Value1;
882 else if (STREQ(buf, "Value2")) supp->skind = Value2;
883 else if (STREQ(buf, "Value4")) supp->skind = Value4;
884 else if (STREQ(buf, "Value8")) supp->skind = Value8;
885 else if (STREQ(buf, "Addr1")) supp->skind = Addr1;
886 else if (STREQ(buf, "Addr2")) supp->skind = Addr2;
887 else if (STREQ(buf, "Addr4")) supp->skind = Addr4;
888 else if (STREQ(buf, "Addr8")) supp->skind = Addr8;
889 else if (STREQ(buf, "Free")) supp->skind = FreeS;
890 else goto syntax_error;
891
892 if (supp->skind == Param) {
893 eof = getLine ( fd, buf, N_BUF );
894 if (eof) goto syntax_error;
895 supp->param = copyStr(buf);
896 }
897
898 eof = getLine ( fd, buf, N_BUF );
899 if (eof) goto syntax_error;
900 supp->caller0 = copyStr(buf);
901 if (!setLocationTy(&(supp->caller0), &(supp->caller0_ty)))
902 goto syntax_error;
903
904 eof = getLine ( fd, buf, N_BUF );
905 if (eof) goto syntax_error;
sewardjde4a1d02002-03-22 01:27:54 +0000906 if (!STREQ(buf, "}")) {
sewardj0873c942002-03-24 09:45:26 +0000907 supp->caller1 = copyStr(buf);
908 if (!setLocationTy(&(supp->caller1), &(supp->caller1_ty)))
sewardjde4a1d02002-03-22 01:27:54 +0000909 goto syntax_error;
sewardj0873c942002-03-24 09:45:26 +0000910
sewardjde4a1d02002-03-22 01:27:54 +0000911 eof = getLine ( fd, buf, N_BUF );
912 if (eof) goto syntax_error;
913 if (!STREQ(buf, "}")) {
sewardj0873c942002-03-24 09:45:26 +0000914 supp->caller2 = copyStr(buf);
915 if (!setLocationTy(&(supp->caller2), &(supp->caller2_ty)))
sewardjde4a1d02002-03-22 01:27:54 +0000916 goto syntax_error;
sewardj0873c942002-03-24 09:45:26 +0000917
sewardjde4a1d02002-03-22 01:27:54 +0000918 eof = getLine ( fd, buf, N_BUF );
sewardj0873c942002-03-24 09:45:26 +0000919 if (eof) goto syntax_error;
920 if (!STREQ(buf, "}")) {
921 supp->caller3 = copyStr(buf);
922 if (!setLocationTy(&(supp->caller3), &(supp->caller3_ty)))
923 goto syntax_error;
924
925 eof = getLine ( fd, buf, N_BUF );
926 if (eof || !STREQ(buf, "}")) goto syntax_error;
927 }
sewardjde4a1d02002-03-22 01:27:54 +0000928 }
929 }
930
931 supp->next = vg_suppressions;
932 vg_suppressions = supp;
933 }
934
935 VG_(close)(fd);
936 return;
937
938 syntax_error:
939 if (eof) {
940 VG_(message)(Vg_UserMsg,
941 "FATAL: in suppressions file `%s': unexpected EOF",
942 filename );
943 } else {
944 VG_(message)(Vg_UserMsg,
945 "FATAL: in suppressions file `%s': syntax error on: %s",
946 filename, buf );
947 }
948 VG_(close)(fd);
949 VG_(message)(Vg_UserMsg, "exiting now.");
950 VG_(exit)(1);
951
952# undef N_BUF
953}
954
955
956void VG_(load_suppressions) ( void )
957{
958 Int i;
959 vg_suppressions = NULL;
960 for (i = 0; i < VG_(clo_n_suppressions); i++) {
961 if (VG_(clo_verbosity) > 1) {
962 VG_(message)(Vg_UserMsg, "Reading suppressions file: %s",
963 VG_(clo_suppressions)[i] );
964 }
965 load_one_suppressions_file( VG_(clo_suppressions)[i] );
966 }
967}
968
969
970/* Does an error context match a suppression? ie is this a
971 suppressible error? If so, return a pointer to the Suppression
972 record, otherwise NULL.
973 Tries to minimise the number of calls to what_fn_is_this since they
974 are expensive.
975*/
976static Suppression* is_suppressible_error ( ErrContext* ec )
977{
978# define STREQ(s1,s2) (s1 != NULL && s2 != NULL \
979 && VG_(strcmp)((s1),(s2))==0)
980
981 Char caller0_obj[M_VG_ERRTXT];
982 Char caller0_fun[M_VG_ERRTXT];
983 Char caller1_obj[M_VG_ERRTXT];
984 Char caller1_fun[M_VG_ERRTXT];
985 Char caller2_obj[M_VG_ERRTXT];
986 Char caller2_fun[M_VG_ERRTXT];
987 Char caller3_obj[M_VG_ERRTXT];
988 Char caller3_fun[M_VG_ERRTXT];
989
990 Suppression* su;
991 Int su_size;
992
993 /* vg_what_fn_or_object_is_this returns:
994 <function_name> or
995 <object_name> or
996 ???
997 so the strings in the suppression file should match these.
998 */
999
1000 /* Initialise these strs so they are always safe to compare, even
1001 if what_fn_or_object_is_this doesn't write anything to them. */
1002 caller0_obj[0] = caller1_obj[0] = caller2_obj[0] = caller3_obj[0] = 0;
1003 caller0_fun[0] = caller1_fun[0] = caller2_obj[0] = caller3_obj[0] = 0;
1004
1005 VG_(what_obj_and_fun_is_this)
1006 ( ec->where->eips[0], caller0_obj, M_VG_ERRTXT,
1007 caller0_fun, M_VG_ERRTXT );
1008 VG_(what_obj_and_fun_is_this)
1009 ( ec->where->eips[1], caller1_obj, M_VG_ERRTXT,
1010 caller1_fun, M_VG_ERRTXT );
1011
1012 if (VG_(clo_backtrace_size) > 2) {
1013 VG_(what_obj_and_fun_is_this)
1014 ( ec->where->eips[2], caller2_obj, M_VG_ERRTXT,
1015 caller2_fun, M_VG_ERRTXT );
1016
1017 if (VG_(clo_backtrace_size) > 3) {
1018 VG_(what_obj_and_fun_is_this)
1019 ( ec->where->eips[3], caller3_obj, M_VG_ERRTXT,
1020 caller3_fun, M_VG_ERRTXT );
1021 }
1022 }
1023
1024 /* See if the error context matches any suppression. */
1025 for (su = vg_suppressions; su != NULL; su = su->next) {
1026 switch (su->skind) {
1027 case FreeS:
1028 case Param: case Value0: su_size = 0; break;
1029 case Value1: case Addr1: su_size = 1; break;
1030 case Value2: case Addr2: su_size = 2; break;
1031 case Value4: case Addr4: su_size = 4; break;
1032 case Value8: case Addr8: su_size = 8; break;
1033 default: VG_(panic)("errcontext_matches_suppression");
1034 }
1035 switch (su->skind) {
1036 case Param:
1037 if (ec->ekind != ParamErr) continue;
1038 if (!STREQ(su->param, ec->syscall_param)) continue;
1039 break;
1040 case Value0: case Value1: case Value2: case Value4: case Value8:
1041 if (ec->ekind != ValueErr) continue;
1042 if (ec->size != su_size) continue;
1043 break;
1044 case Addr1: case Addr2: case Addr4: case Addr8:
1045 if (ec->ekind != AddrErr) continue;
1046 if (ec->size != su_size) continue;
1047 break;
1048 case FreeS:
1049 if (ec->ekind != FreeErr && ec->ekind != FreeMismatchErr) continue;
1050 break;
1051 }
1052
1053 switch (su->caller0_ty) {
1054 case ObjName: if (!VG_(stringMatch)(su->caller0,
1055 caller0_obj)) continue;
1056 break;
1057 case FunName: if (!VG_(stringMatch)(su->caller0,
1058 caller0_fun)) continue;
1059 break;
1060 default: goto baaaad;
1061 }
1062
sewardj0873c942002-03-24 09:45:26 +00001063 if (su->caller1 != NULL) {
1064 vg_assert(VG_(clo_backtrace_size) >= 2);
1065 switch (su->caller1_ty) {
1066 case ObjName: if (!VG_(stringMatch)(su->caller1,
1067 caller1_obj)) continue;
1068 break;
1069 case FunName: if (!VG_(stringMatch)(su->caller1,
1070 caller1_fun)) continue;
1071 break;
1072 default: goto baaaad;
1073 }
sewardjde4a1d02002-03-22 01:27:54 +00001074 }
1075
1076 if (VG_(clo_backtrace_size) > 2 && su->caller2 != NULL) {
1077 switch (su->caller2_ty) {
1078 case ObjName: if (!VG_(stringMatch)(su->caller2,
1079 caller2_obj)) continue;
1080 break;
1081 case FunName: if (!VG_(stringMatch)(su->caller2,
1082 caller2_fun)) continue;
1083 break;
1084 default: goto baaaad;
1085 }
1086 }
1087
1088 if (VG_(clo_backtrace_size) > 3 && su->caller3 != NULL) {
1089 switch (su->caller3_ty) {
1090 case ObjName: if (!VG_(stringMatch)(su->caller3,
1091 caller3_obj)) continue;
1092 break;
1093 case FunName: if (!VG_(stringMatch)(su->caller3,
1094 caller3_fun)) continue;
1095 break;
1096 default: goto baaaad;
1097 }
1098 }
1099
1100 return su;
1101 }
1102
1103 return NULL;
1104
1105 baaaad:
1106 VG_(panic)("is_suppressible_error");
1107
1108# undef STREQ
1109}
1110
1111/*--------------------------------------------------------------------*/
1112/*--- end vg_errcontext.c ---*/
1113/*--------------------------------------------------------------------*/