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