blob: 3040fb2f3a3a8610d2d109e214a9aebba1fe4ff6 [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
2/*--------------------------------------------------------------------*/
3/*--- Management of error messages. vg_errcontext.c ---*/
4/*--------------------------------------------------------------------*/
5
6/*
njnc9539842002-10-02 13:26:35 +00007 This file is part of Valgrind, an extensible x86 protected-mode
8 emulator for monitoring program execution on x86-Unixes.
sewardjde4a1d02002-03-22 01:27:54 +00009
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
njn25e49d8e72002-09-23 09:36:25 +000028 The GNU General Public License is contained in the file COPYING.
sewardjde4a1d02002-03-22 01:27:54 +000029*/
30
31#include "vg_include.h"
sewardjde4a1d02002-03-22 01:27:54 +000032
33/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +000034/*--- Globals ---*/
sewardjde4a1d02002-03-22 01:27:54 +000035/*------------------------------------------------------------*/
36
sewardjde4a1d02002-03-22 01:27:54 +000037/* The list of error contexts found, both suppressed and unsuppressed.
38 Initially empty, and grows as errors are detected. */
njn810086f2002-11-14 12:42:47 +000039static Error* vg_errors = NULL;
sewardjde4a1d02002-03-22 01:27:54 +000040
41/* The list of suppression directives, as read from the specified
42 suppressions file. */
njn810086f2002-11-14 12:42:47 +000043static Supp* vg_suppressions = NULL;
sewardjde4a1d02002-03-22 01:27:54 +000044
sewardj99aac972002-12-26 01:53:45 +000045/* And a helper function so the leak detector can get hold of it. */
46Supp* VG_(get_suppressions) ( void ) { return vg_suppressions; }
47
sewardjde4a1d02002-03-22 01:27:54 +000048/* Running count of unsuppressed errors detected. */
49static UInt vg_n_errs_found = 0;
50
51/* Running count of suppressed errors detected. */
52static UInt vg_n_errs_suppressed = 0;
53
54/* forwards ... */
njn810086f2002-11-14 12:42:47 +000055static Supp* is_suppressible_error ( Error* err );
sewardjde4a1d02002-03-22 01:27:54 +000056
57
58/*------------------------------------------------------------*/
59/*--- Helper fns ---*/
60/*------------------------------------------------------------*/
61
sewardjde4a1d02002-03-22 01:27:54 +000062/* Compare error contexts, to detect duplicates. Note that if they
63 are otherwise the same, the faulting addrs and associated rwoffsets
64 are allowed to be different. */
njn810086f2002-11-14 12:42:47 +000065static Bool eq_Error ( VgRes res, Error* e1, Error* e2 )
sewardjde4a1d02002-03-22 01:27:54 +000066{
njn810086f2002-11-14 12:42:47 +000067 if (e1->ekind != e2->ekind)
sewardjde4a1d02002-03-22 01:27:54 +000068 return False;
njn25e49d8e72002-09-23 09:36:25 +000069 if (!VG_(eq_ExeContext)(res, e1->where, e2->where))
sewardjde4a1d02002-03-22 01:27:54 +000070 return False;
71
njn810086f2002-11-14 12:42:47 +000072 switch (e1->ekind) {
sewardj4dced352002-06-04 22:54:20 +000073 case PThreadErr:
njn25e49d8e72002-09-23 09:36:25 +000074 vg_assert(VG_(needs).core_errors);
njn810086f2002-11-14 12:42:47 +000075 if (e1->string == e2->string)
sewardj4dced352002-06-04 22:54:20 +000076 return True;
njn810086f2002-11-14 12:42:47 +000077 if (0 == VG_(strcmp)(e1->string, e2->string))
sewardj4dced352002-06-04 22:54:20 +000078 return True;
79 return False;
sewardjde4a1d02002-03-22 01:27:54 +000080 default:
njn25e49d8e72002-09-23 09:36:25 +000081 if (VG_(needs).skin_errors)
njn810086f2002-11-14 12:42:47 +000082 return SK_(eq_SkinError)(res, e1, e2);
njn25e49d8e72002-09-23 09:36:25 +000083 else {
84 VG_(printf)("\nUnhandled error type: %u. VG_(needs).skin_errors\n"
85 "probably needs to be set.\n",
njn810086f2002-11-14 12:42:47 +000086 e1->ekind);
njne427a662002-10-02 11:08:25 +000087 VG_(skin_panic)("unhandled error type");
njn25e49d8e72002-09-23 09:36:25 +000088 }
sewardjde4a1d02002-03-22 01:27:54 +000089 }
90}
91
njn810086f2002-11-14 12:42:47 +000092static void pp_Error ( Error* err, Bool printCount )
sewardjde4a1d02002-03-22 01:27:54 +000093{
sewardjde4a1d02002-03-22 01:27:54 +000094 if (printCount)
njn25e49d8e72002-09-23 09:36:25 +000095 VG_(message)(Vg_UserMsg, "Observed %d times:", err->count );
96 if (err->tid > 1)
97 VG_(message)(Vg_UserMsg, "Thread %d:", err->tid );
98
njn810086f2002-11-14 12:42:47 +000099 switch (err->ekind) {
sewardj4dced352002-06-04 22:54:20 +0000100 case PThreadErr:
njn25e49d8e72002-09-23 09:36:25 +0000101 vg_assert(VG_(needs).core_errors);
njn810086f2002-11-14 12:42:47 +0000102 VG_(message)(Vg_UserMsg, "%s", err->string );
njn25e49d8e72002-09-23 09:36:25 +0000103 VG_(pp_ExeContext)(err->where);
sewardj4dced352002-06-04 22:54:20 +0000104 break;
sewardjde4a1d02002-03-22 01:27:54 +0000105 default:
njn25e49d8e72002-09-23 09:36:25 +0000106 if (VG_(needs).skin_errors)
njn43c799e2003-04-08 00:08:52 +0000107 SK_(pp_SkinError)( err );
njn25e49d8e72002-09-23 09:36:25 +0000108 else {
109 VG_(printf)("\nUnhandled error type: %u. VG_(needs).skin_errors\n"
110 "probably needs to be set?\n",
njn810086f2002-11-14 12:42:47 +0000111 err->ekind);
njne427a662002-10-02 11:08:25 +0000112 VG_(skin_panic)("unhandled error type");
njn25e49d8e72002-09-23 09:36:25 +0000113 }
sewardjde4a1d02002-03-22 01:27:54 +0000114 }
115}
116
sewardjde4a1d02002-03-22 01:27:54 +0000117/* Figure out if we want to attach for GDB for this error, possibly
118 by asking the user. */
njn43c799e2003-04-08 00:08:52 +0000119Bool VG_(is_action_requested) ( Char* action, Bool* clo )
sewardjde4a1d02002-03-22 01:27:54 +0000120{
121 Char ch, ch2;
122 Int res;
123
njn43c799e2003-04-08 00:08:52 +0000124 if (*clo == False)
sewardjde4a1d02002-03-22 01:27:54 +0000125 return False;
126
127 VG_(message)(Vg_UserMsg, "");
128
129 again:
130 VG_(printf)(
131 "==%d== "
njn43c799e2003-04-08 00:08:52 +0000132 "---- %s ? --- [Return/N/n/Y/y/C/c] ---- ",
133 VG_(getpid)(), action
sewardjde4a1d02002-03-22 01:27:54 +0000134 );
135
136 res = VG_(read)(0 /*stdin*/, &ch, 1);
137 if (res != 1) goto ioerror;
138 /* res == 1 */
139 if (ch == '\n') return False;
140 if (ch != 'N' && ch != 'n' && ch != 'Y' && ch != 'y'
141 && ch != 'C' && ch != 'c') goto again;
142
143 res = VG_(read)(0 /*stdin*/, &ch2, 1);
144 if (res != 1) goto ioerror;
145 if (ch2 != '\n') goto again;
146
njn43c799e2003-04-08 00:08:52 +0000147 /* No, don't want to do action. */
sewardjde4a1d02002-03-22 01:27:54 +0000148 if (ch == 'n' || ch == 'N') return False;
njn43c799e2003-04-08 00:08:52 +0000149 /* Yes, want to do action. */
sewardjde4a1d02002-03-22 01:27:54 +0000150 if (ch == 'y' || ch == 'Y') return True;
njn43c799e2003-04-08 00:08:52 +0000151 /* No, don't want to do action, and don't ask again either. */
sewardjde4a1d02002-03-22 01:27:54 +0000152 vg_assert(ch == 'c' || ch == 'C');
153
154 ioerror:
njn43c799e2003-04-08 00:08:52 +0000155 *clo = False;
sewardjde4a1d02002-03-22 01:27:54 +0000156 return False;
157}
158
159
njn25e49d8e72002-09-23 09:36:25 +0000160/* I've gone all object-oriented... initialisation depends on where the
161 error comes from:
162
163 - If from generated code (tst == NULL), the %EIP/%EBP values that we
164 need in order to create proper error messages are picked up out of
165 VG_(baseBlock) rather than from the thread table (vg_threads in
166 vg_scheduler.c).
167
168 - If not from generated code but in response to requests passed back to
169 the scheduler (tst != NULL), we pick up %EIP/%EBP values from the
170 stored thread state, not from VG_(baseBlock).
171*/
172static __inline__
njn43c799e2003-04-08 00:08:52 +0000173void construct_error ( Error* err, ThreadState* tst, ErrorKind ekind, Addr a,
174 Char* s, void* extra, ExeContext* where )
sewardjde4a1d02002-03-22 01:27:54 +0000175{
njn810086f2002-11-14 12:42:47 +0000176 /* Core-only parts */
njn25e49d8e72002-09-23 09:36:25 +0000177 err->next = NULL;
178 err->supp = NULL;
179 err->count = 1;
njn43c799e2003-04-08 00:08:52 +0000180 if (NULL == where)
181 err->where = VG_(get_ExeContext)( tst );
182 else
183 err->where = where;
njn1d6c4bc2002-11-21 13:38:08 +0000184
njn25e49d8e72002-09-23 09:36:25 +0000185 if (NULL == tst) {
186 err->tid = VG_(get_current_tid)();
njn25e49d8e72002-09-23 09:36:25 +0000187 err->m_eip = VG_(baseBlock)[VGOFF_(m_eip)];
188 err->m_esp = VG_(baseBlock)[VGOFF_(m_esp)];
189 err->m_ebp = VG_(baseBlock)[VGOFF_(m_ebp)];
190 } else {
njn25e49d8e72002-09-23 09:36:25 +0000191 err->tid = tst->tid;
192 err->m_eip = tst->m_eip;
193 err->m_esp = tst->m_esp;
194 err->m_ebp = tst->m_ebp;
195 }
196
njn810086f2002-11-14 12:42:47 +0000197 /* Skin-relevant parts */
198 err->ekind = ekind;
199 err->addr = a;
200 err->string = s;
201 err->extra = extra;
njn25e49d8e72002-09-23 09:36:25 +0000202
203 /* sanity... */
204 vg_assert(err->tid >= 0 && err->tid < VG_N_THREADS);
205}
206
njn43c799e2003-04-08 00:08:52 +0000207void VG_(gen_suppression)(Error* err)
208{
209 UInt i;
210 UChar buf[M_VG_ERRTXT];
211 ExeContext* ec = VG_(get_error_where)(err);
212 Int stop_at = VG_(clo_backtrace_size);
213 Char* name = SK_(get_error_name)(err);
214
215 if (NULL == name) {
216 VG_(message)(Vg_UserMsg, "(skin does not allow error to be suppressed)");
217 return;
218 }
219
220 if (stop_at > 3) stop_at = 3; /* At most three names */
221 vg_assert(stop_at > 0);
222
223 VG_(printf)("{\n");
224 VG_(printf)(" <insert a suppression name here>\n");
225 VG_(printf)(" %s:%s\n", VG_(details).name, name);
226 SK_(print_extra_suppression_info)(err);
227
228 /* This loop condensed from VG_(mini_stack_dump)() */
229 i = 0;
230 do {
231 Addr eip = ec->eips[i];
232 if (i > 0)
233 eip--; /* point to calling line */
234
235 if ( VG_(get_fnname_nodemangle) (eip, buf, M_VG_ERRTXT) ) {
236 VG_(printf)(" fun:%s\n", buf);
237 } else if ( VG_(get_objname)(eip, buf, M_VG_ERRTXT) ) {
238 VG_(printf)(" obj:%s\n", buf);
239 } else {
240 VG_(printf)(" ???:??? "
241 "# unknown, suppression will not work, sorry)\n");
242 }
243 i++;
244 } while (i < stop_at && ec->eips[i] != 0);
245
246 VG_(printf)("}\n");
247}
248
249void do_actions_on_error(Error* err)
250{
251 /* Perhaps we want a GDB attach at this point? */
252 if (VG_(is_action_requested)( "Attach to GDB", & VG_(clo_GDB_attach) )) {
253 VG_(swizzle_esp_then_start_GDB)(
254 err->m_eip, err->m_esp, err->m_ebp);
255 }
256 /* Or maybe we want to generate the error's suppression? */
257 if (VG_(is_action_requested)( "Print suppression",
258 & VG_(clo_gen_suppressions) )) {
259 VG_(gen_suppression)(err);
260 }
261}
262
263/* Shared between VG_(maybe_record_error)() and VG_(unique_error)(),
264 just for pretty printing purposes. */
265static Bool is_first_shown_context = True;
266
njn25e49d8e72002-09-23 09:36:25 +0000267/* Top-level entry point to the error management subsystem.
268 All detected errors are notified here; this routine decides if/when the
269 user should see the error. */
270void VG_(maybe_record_error) ( ThreadState* tst,
271 ErrorKind ekind, Addr a, Char* s, void* extra )
272{
njn810086f2002-11-14 12:42:47 +0000273 Error err;
274 Error* p;
275 Error* p_prev;
njn43c799e2003-04-08 00:08:52 +0000276 UInt extra_size;
njn810086f2002-11-14 12:42:47 +0000277 VgRes exe_res = Vg_MedRes;
njn810086f2002-11-14 12:42:47 +0000278 static Bool stopping_message = False;
279 static Bool slowdown_message = False;
280 static Int vg_n_errs_shown = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000281
sewardjf2537be2002-04-24 21:03:47 +0000282 /* After M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN different errors have
283 been found, or M_VG_COLLECT_NO_ERRORS_AFTER_FOUND total errors
284 have been found, just refuse to collect any more. This stops
285 the burden of the error-management system becoming excessive in
286 extremely buggy programs, although it does make it pretty
287 pointless to continue the Valgrind run after this point. */
sewardj2e432902002-06-13 20:44:00 +0000288 if (VG_(clo_error_limit)
sewardj72f98ff2002-06-13 17:23:38 +0000289 && (vg_n_errs_shown >= M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN
290 || vg_n_errs_found >= M_VG_COLLECT_NO_ERRORS_AFTER_FOUND)) {
sewardjde4a1d02002-03-22 01:27:54 +0000291 if (!stopping_message) {
292 VG_(message)(Vg_UserMsg, "");
sewardjf2537be2002-04-24 21:03:47 +0000293
294 if (vg_n_errs_shown >= M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN) {
295 VG_(message)(Vg_UserMsg,
296 "More than %d different errors detected. "
297 "I'm not reporting any more.",
298 M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN );
299 } else {
300 VG_(message)(Vg_UserMsg,
301 "More than %d total errors detected. "
302 "I'm not reporting any more.",
303 M_VG_COLLECT_NO_ERRORS_AFTER_FOUND );
304 }
305
sewardjde4a1d02002-03-22 01:27:54 +0000306 VG_(message)(Vg_UserMsg,
sewardjf2537be2002-04-24 21:03:47 +0000307 "Final error counts will be inaccurate. Go fix your program!");
sewardj72f98ff2002-06-13 17:23:38 +0000308 VG_(message)(Vg_UserMsg,
sewardj2e432902002-06-13 20:44:00 +0000309 "Rerun with --error-limit=no to disable this cutoff. Note");
sewardj72f98ff2002-06-13 17:23:38 +0000310 VG_(message)(Vg_UserMsg,
njn25e49d8e72002-09-23 09:36:25 +0000311 "that errors may occur in your program without prior warning from");
sewardj72f98ff2002-06-13 17:23:38 +0000312 VG_(message)(Vg_UserMsg,
313 "Valgrind, because errors are no longer being displayed.");
sewardjde4a1d02002-03-22 01:27:54 +0000314 VG_(message)(Vg_UserMsg, "");
315 stopping_message = True;
316 }
317 return;
318 }
319
320 /* After M_VG_COLLECT_ERRORS_SLOWLY_AFTER different errors have
321 been found, be much more conservative about collecting new
322 ones. */
323 if (vg_n_errs_shown >= M_VG_COLLECT_ERRORS_SLOWLY_AFTER) {
njn25e49d8e72002-09-23 09:36:25 +0000324 exe_res = Vg_LowRes;
sewardjde4a1d02002-03-22 01:27:54 +0000325 if (!slowdown_message) {
326 VG_(message)(Vg_UserMsg, "");
327 VG_(message)(Vg_UserMsg,
328 "More than %d errors detected. Subsequent errors",
329 M_VG_COLLECT_ERRORS_SLOWLY_AFTER);
330 VG_(message)(Vg_UserMsg,
331 "will still be recorded, but in less detail than before.");
332 slowdown_message = True;
333 }
334 }
335
njn25e49d8e72002-09-23 09:36:25 +0000336 /* Build ourselves the error */
njn43c799e2003-04-08 00:08:52 +0000337 construct_error ( &err, tst, ekind, a, s, extra, NULL );
sewardjde4a1d02002-03-22 01:27:54 +0000338
339 /* First, see if we've got an error record matching this one. */
njn25e49d8e72002-09-23 09:36:25 +0000340 p = vg_errors;
sewardjde4a1d02002-03-22 01:27:54 +0000341 p_prev = NULL;
342 while (p != NULL) {
njn810086f2002-11-14 12:42:47 +0000343 if (eq_Error(exe_res, p, &err)) {
sewardjde4a1d02002-03-22 01:27:54 +0000344 /* Found it. */
345 p->count++;
346 if (p->supp != NULL) {
347 /* Deal correctly with suppressed errors. */
348 p->supp->count++;
349 vg_n_errs_suppressed++;
350 } else {
351 vg_n_errs_found++;
352 }
353
354 /* Move p to the front of the list so that future searches
355 for it are faster. */
356 if (p_prev != NULL) {
357 vg_assert(p_prev->next == p);
358 p_prev->next = p->next;
njn25e49d8e72002-09-23 09:36:25 +0000359 p->next = vg_errors;
360 vg_errors = p;
sewardjde4a1d02002-03-22 01:27:54 +0000361 }
362 return;
363 }
364 p_prev = p;
365 p = p->next;
366 }
367
368 /* Didn't see it. Copy and add. */
369
njn43c799e2003-04-08 00:08:52 +0000370 /* OK, we're really going to collect it. The context is on the stack and
371 will disappear shortly, so we must copy it. First do the main
372 (non-`extra') part.
njn25e49d8e72002-09-23 09:36:25 +0000373
njn43c799e2003-04-08 00:08:52 +0000374 Then SK_(update_extra) can update the `extra' part. This is for when
375 there are more details to fill in which take time to work out but
376 don't affect our earlier decision to include the error -- by
njn25e49d8e72002-09-23 09:36:25 +0000377 postponing those details until now, we avoid the extra work in the
njn810086f2002-11-14 12:42:47 +0000378 case where we ignore the error. Ugly.
njn43c799e2003-04-08 00:08:52 +0000379
380 Then, if there is an `extra' part, copy it too, using the size that
381 SK_(update_extra) returned.
382 */
383
384 /* copy main part */
njn810086f2002-11-14 12:42:47 +0000385 p = VG_(arena_malloc)(VG_AR_ERRORS, sizeof(Error));
njn25e49d8e72002-09-23 09:36:25 +0000386 *p = err;
njn43c799e2003-04-08 00:08:52 +0000387
388 /* update `extra' */
389 extra_size = SK_(update_extra)(p);
390
391 /* copy `extra' if there is one */
392 if (NULL != p->extra) {
393 void* new_extra = VG_(malloc)(extra_size);
394 VG_(memcpy)(new_extra, p->extra, extra_size);
395 p->extra = new_extra;
396 }
397
njn25e49d8e72002-09-23 09:36:25 +0000398 p->next = vg_errors;
399 p->supp = is_suppressible_error(&err);
400 vg_errors = p;
sewardjde4a1d02002-03-22 01:27:54 +0000401 if (p->supp == NULL) {
402 vg_n_errs_found++;
403 if (!is_first_shown_context)
404 VG_(message)(Vg_UserMsg, "");
njn43c799e2003-04-08 00:08:52 +0000405 pp_Error(p, False);
sewardjde4a1d02002-03-22 01:27:54 +0000406 is_first_shown_context = False;
407 vg_n_errs_shown++;
njn43c799e2003-04-08 00:08:52 +0000408 do_actions_on_error(p);
sewardjde4a1d02002-03-22 01:27:54 +0000409 } else {
410 vg_n_errs_suppressed++;
411 p->supp->count++;
412 }
413}
414
njn43c799e2003-04-08 00:08:52 +0000415/* Second top-level entry point to the error management subsystem, for
416 errors that the skin want to report immediately, eg. because they're
417 guaranteed to only happen once. This avoids all the recording and
418 comparing stuff. But they can be suppressed; returns True if it is
419 suppressed. Bool `print_error' dictates whether to print the error. */
420Bool VG_(unique_error) ( ThreadState* tst, ErrorKind ekind, Addr a, Char* s,
421 void* extra, ExeContext* where, Bool print_error )
422{
423 Error err;
424
425 /* Build ourselves the error */
426 construct_error ( &err, tst, ekind, a, s, extra, where );
427
428 /* Unless it's suppressed, we're going to show it. Don't need to make
429 a copy, because it's only temporary anyway.
430
431 Then update the `extra' part with SK_(update_extra), because that can
432 have an affect on whether it's suppressed. Ignore the size return
433 value of SK_(update_extra), because we're not copying `extra'. */
434 (void)SK_(update_extra)(&err);
435
436 if (NULL == is_suppressible_error(&err)) {
437 vg_n_errs_found++;
438
439 if (print_error) {
440 if (!is_first_shown_context)
441 VG_(message)(Vg_UserMsg, "");
442 pp_Error(&err, False);
443 is_first_shown_context = False;
444 }
445 do_actions_on_error(&err);
446
447 return False;
448
449 } else {
450 vg_n_errs_suppressed++;
451 return True;
452 }
453}
454
sewardjde4a1d02002-03-22 01:27:54 +0000455
sewardjde4a1d02002-03-22 01:27:54 +0000456/*------------------------------------------------------------*/
457/*--- Exported fns ---*/
458/*------------------------------------------------------------*/
459
njn25e49d8e72002-09-23 09:36:25 +0000460/* These are called not from generated code but from the scheduler */
sewardj8c824512002-04-14 04:16:48 +0000461
njn25e49d8e72002-09-23 09:36:25 +0000462void VG_(record_pthread_error) ( ThreadId tid, Char* msg )
sewardjde4a1d02002-03-22 01:27:54 +0000463{
njn25e49d8e72002-09-23 09:36:25 +0000464 if (! VG_(needs).core_errors) return;
465 VG_(maybe_record_error)( &VG_(threads)[tid], PThreadErr, /*addr*/0, msg,
466 /*extra*/NULL );
sewardjde4a1d02002-03-22 01:27:54 +0000467}
468
sewardj8c824512002-04-14 04:16:48 +0000469/*------------------------------*/
470
sewardjde4a1d02002-03-22 01:27:54 +0000471void VG_(show_all_errors) ( void )
472{
njn810086f2002-11-14 12:42:47 +0000473 Int i, n_min;
474 Int n_err_contexts, n_supp_contexts;
475 Error *p, *p_min;
476 Supp *su;
477 Bool any_supp;
sewardjde4a1d02002-03-22 01:27:54 +0000478
479 if (VG_(clo_verbosity) == 0)
480 return;
481
482 n_err_contexts = 0;
njn25e49d8e72002-09-23 09:36:25 +0000483 for (p = vg_errors; p != NULL; p = p->next) {
sewardjde4a1d02002-03-22 01:27:54 +0000484 if (p->supp == NULL)
485 n_err_contexts++;
486 }
487
488 n_supp_contexts = 0;
489 for (su = vg_suppressions; su != NULL; su = su->next) {
490 if (su->count > 0)
491 n_supp_contexts++;
492 }
493
494 VG_(message)(Vg_UserMsg,
495 "ERROR SUMMARY: "
496 "%d errors from %d contexts (suppressed: %d from %d)",
497 vg_n_errs_found, n_err_contexts,
498 vg_n_errs_suppressed, n_supp_contexts );
499
500 if (VG_(clo_verbosity) <= 1)
501 return;
502
503 /* Print the contexts in order of increasing error count. */
504 for (i = 0; i < n_err_contexts; i++) {
505 n_min = (1 << 30) - 1;
506 p_min = NULL;
njn25e49d8e72002-09-23 09:36:25 +0000507 for (p = vg_errors; p != NULL; p = p->next) {
sewardjde4a1d02002-03-22 01:27:54 +0000508 if (p->supp != NULL) continue;
509 if (p->count < n_min) {
510 n_min = p->count;
511 p_min = p;
512 }
513 }
njne427a662002-10-02 11:08:25 +0000514 if (p_min == NULL) VG_(skin_panic)("show_all_errors()");
sewardjde4a1d02002-03-22 01:27:54 +0000515
516 VG_(message)(Vg_UserMsg, "");
517 VG_(message)(Vg_UserMsg, "%d errors in context %d of %d:",
518 p_min->count,
519 i+1, n_err_contexts);
njn810086f2002-11-14 12:42:47 +0000520 pp_Error( p_min, False );
sewardjde4a1d02002-03-22 01:27:54 +0000521
522 if ((i+1 == VG_(clo_dump_error))) {
sewardj1e8cdc92002-04-18 11:37:52 +0000523 VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to below NULLs */,
sewardj22854b92002-11-30 14:00:47 +0000524 p_min->where->eips[0], NULL, NULL, NULL, NULL );
sewardjde4a1d02002-03-22 01:27:54 +0000525 }
526
527 p_min->count = 1 << 30;
528 }
529
530 if (n_supp_contexts > 0)
531 VG_(message)(Vg_DebugMsg, "");
532 any_supp = False;
533 for (su = vg_suppressions; su != NULL; su = su->next) {
534 if (su->count > 0) {
535 any_supp = True;
njn25e49d8e72002-09-23 09:36:25 +0000536 VG_(message)(Vg_DebugMsg, "supp: %4d %s", su->count, su->sname);
sewardjde4a1d02002-03-22 01:27:54 +0000537 }
538 }
539
540 if (n_err_contexts > 0) {
541 if (any_supp)
542 VG_(message)(Vg_UserMsg, "");
543 VG_(message)(Vg_UserMsg,
544 "IN SUMMARY: "
545 "%d errors from %d contexts (suppressed: %d from %d)",
546 vg_n_errs_found, n_err_contexts,
547 vg_n_errs_suppressed,
548 n_supp_contexts );
549 VG_(message)(Vg_UserMsg, "");
550 }
551}
552
553/*------------------------------------------------------------*/
554/*--- Standard suppressions ---*/
555/*------------------------------------------------------------*/
556
557/* Get a non-blank, non-comment line of at most nBuf chars from fd.
558 Skips leading spaces on the line. Return True if EOF was hit instead.
559*/
560
561#define VG_ISSPACE(ch) (((ch)==' ') || ((ch)=='\n') || ((ch)=='\t'))
562
njn4ba5a792002-09-30 10:23:54 +0000563Bool VG_(get_line) ( Int fd, Char* buf, Int nBuf )
sewardjde4a1d02002-03-22 01:27:54 +0000564{
565 Char ch;
566 Int n, i;
567 while (True) {
568 /* First, read until a non-blank char appears. */
569 while (True) {
570 n = VG_(read)(fd, &ch, 1);
571 if (n == 1 && !VG_ISSPACE(ch)) break;
572 if (n == 0) return True;
573 }
574
575 /* Now, read the line into buf. */
576 i = 0;
577 buf[i++] = ch; buf[i] = 0;
578 while (True) {
579 n = VG_(read)(fd, &ch, 1);
580 if (n == 0) return False; /* the next call will return True */
581 if (ch == '\n') break;
582 if (i > 0 && i == nBuf-1) i--;
583 buf[i++] = ch; buf[i] = 0;
584 }
585 while (i > 1 && VG_ISSPACE(buf[i-1])) {
586 i--; buf[i] = 0;
587 };
588
589 /* VG_(printf)("The line is `%s'\n", buf); */
590 /* Ok, we have a line. If a non-comment line, return.
591 If a comment line, start all over again. */
592 if (buf[0] != '#') return False;
593 }
594}
595
596
597/* *p_caller contains the raw name of a caller, supposedly either
598 fun:some_function_name or
599 obj:some_object_name.
600 Set *p_ty accordingly and advance *p_caller over the descriptor
601 (fun: or obj:) part.
602 Returns False if failed.
603*/
njn25e49d8e72002-09-23 09:36:25 +0000604static Bool setLocationTy ( Char** p_caller, SuppLocTy* p_ty )
sewardjde4a1d02002-03-22 01:27:54 +0000605{
606 if (VG_(strncmp)(*p_caller, "fun:", 4) == 0) {
607 (*p_caller) += 4;
608 *p_ty = FunName;
609 return True;
610 }
611 if (VG_(strncmp)(*p_caller, "obj:", 4) == 0) {
612 (*p_caller) += 4;
613 *p_ty = ObjName;
614 return True;
615 }
616 VG_(printf)("location should start with fun: or obj:\n");
617 return False;
618}
619
620
njn11cc9252002-10-07 14:42:59 +0000621/* Look for "skin" in a string like "skin1,skin2,skin3" */
622static __inline__
623Bool skin_name_present(Char *name, Char *names)
624{
625 Bool found;
626 Char *s = NULL; /* Shut gcc up */
627 Int len = VG_(strlen)(name);
628
629 found = (NULL != (s = VG_(strstr)(names, name)) &&
630 (s == names || *(s-1) == ',') &&
631 (*(s+len) == ',' || *(s+len) == '\0')
632 );
633
634 return found;
635}
636
sewardjde4a1d02002-03-22 01:27:54 +0000637/* Read suppressions from the file specified in vg_clo_suppressions
638 and place them in the suppressions list. If there's any difficulty
639 doing this, just give up -- there's no point in trying to recover.
640*/
sewardjde4a1d02002-03-22 01:27:54 +0000641static void load_one_suppressions_file ( Char* filename )
642{
643# define N_BUF 200
njnc40c3a82002-10-02 11:02:27 +0000644 Int fd, i;
645 Bool eof;
646 Char buf[N_BUF+1];
njn11cc9252002-10-07 14:42:59 +0000647 Char* skin_names;
njnc40c3a82002-10-02 11:02:27 +0000648 Char* supp_name;
649
njn25e49d8e72002-09-23 09:36:25 +0000650 fd = VG_(open)( filename, VKI_O_RDONLY, 0 );
sewardjde4a1d02002-03-22 01:27:54 +0000651 if (fd == -1) {
njn25e49d8e72002-09-23 09:36:25 +0000652 VG_(message)(Vg_UserMsg, "FATAL: can't open suppressions file `%s'",
sewardjde4a1d02002-03-22 01:27:54 +0000653 filename );
654 VG_(exit)(1);
655 }
656
657 while (True) {
njn25e49d8e72002-09-23 09:36:25 +0000658 /* Assign and initialise the two suppression halves (core and skin) */
njn810086f2002-11-14 12:42:47 +0000659 Supp* supp;
660 supp = VG_(arena_malloc)(VG_AR_CORE, sizeof(Supp));
sewardjde4a1d02002-03-22 01:27:54 +0000661 supp->count = 0;
njn25e49d8e72002-09-23 09:36:25 +0000662 for (i = 0; i < VG_N_SUPP_CALLERS; i++) supp->caller[i] = NULL;
njn810086f2002-11-14 12:42:47 +0000663 supp->string = supp->extra = NULL;
sewardjde4a1d02002-03-22 01:27:54 +0000664
njn4ba5a792002-09-30 10:23:54 +0000665 eof = VG_(get_line) ( fd, buf, N_BUF );
sewardjde4a1d02002-03-22 01:27:54 +0000666 if (eof) break;
667
njn43c799e2003-04-08 00:08:52 +0000668 if (!VG_STREQ(buf, "{")) goto syntax_error;
sewardjde4a1d02002-03-22 01:27:54 +0000669
njn4ba5a792002-09-30 10:23:54 +0000670 eof = VG_(get_line) ( fd, buf, N_BUF );
njn43c799e2003-04-08 00:08:52 +0000671 if (eof || VG_STREQ(buf, "}")) goto syntax_error;
njn25e49d8e72002-09-23 09:36:25 +0000672 supp->sname = VG_(arena_strdup)(VG_AR_CORE, buf);
sewardjde4a1d02002-03-22 01:27:54 +0000673
njn4ba5a792002-09-30 10:23:54 +0000674 eof = VG_(get_line) ( fd, buf, N_BUF );
njn25e49d8e72002-09-23 09:36:25 +0000675
sewardjde4a1d02002-03-22 01:27:54 +0000676 if (eof) goto syntax_error;
sewardjde4a1d02002-03-22 01:27:54 +0000677
njn11cc9252002-10-07 14:42:59 +0000678 /* Check it has the "skin1,skin2,...:supp" form (look for ':') */
njnc40c3a82002-10-02 11:02:27 +0000679 i = 0;
680 while (True) {
681 if (buf[i] == ':') break;
682 if (buf[i] == '\0') goto syntax_error;
683 i++;
njn25e49d8e72002-09-23 09:36:25 +0000684 }
njnc40c3a82002-10-02 11:02:27 +0000685 buf[i] = '\0'; /* Replace ':', splitting into two strings */
686
njn11cc9252002-10-07 14:42:59 +0000687 skin_names = & buf[0];
688 supp_name = & buf[i+1];
njnc40c3a82002-10-02 11:02:27 +0000689
njn11cc9252002-10-07 14:42:59 +0000690 /* Is it a core suppression? */
691 if (VG_(needs).core_errors && skin_name_present("core", skin_names))
njnc40c3a82002-10-02 11:02:27 +0000692 {
njn43c799e2003-04-08 00:08:52 +0000693 if (VG_STREQ(supp_name, "PThread"))
njn810086f2002-11-14 12:42:47 +0000694 supp->skind = PThreadSupp;
njnc40c3a82002-10-02 11:02:27 +0000695 else
696 goto syntax_error;
697 }
698
njn11cc9252002-10-07 14:42:59 +0000699 /* Is it a skin suppression? */
700 else if (VG_(needs).skin_errors &&
701 skin_name_present(VG_(details).name, skin_names))
njnc40c3a82002-10-02 11:02:27 +0000702 {
njn810086f2002-11-14 12:42:47 +0000703 if (SK_(recognised_suppression)(supp_name, supp))
njnc40c3a82002-10-02 11:02:27 +0000704 {
njn810086f2002-11-14 12:42:47 +0000705 /* Do nothing, function fills in supp->skind */
njnc40c3a82002-10-02 11:02:27 +0000706 } else
707 goto syntax_error;
708 }
709
njn25e49d8e72002-09-23 09:36:25 +0000710 else {
njnc40c3a82002-10-02 11:02:27 +0000711 /* Ignore rest of suppression */
njn25e49d8e72002-09-23 09:36:25 +0000712 while (True) {
njn4ba5a792002-09-30 10:23:54 +0000713 eof = VG_(get_line) ( fd, buf, N_BUF );
njn25e49d8e72002-09-23 09:36:25 +0000714 if (eof) goto syntax_error;
njn43c799e2003-04-08 00:08:52 +0000715 if (VG_STREQ(buf, "}"))
njn25e49d8e72002-09-23 09:36:25 +0000716 break;
717 }
718 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000719 }
720
njn25e49d8e72002-09-23 09:36:25 +0000721 if (VG_(needs).skin_errors &&
njn810086f2002-11-14 12:42:47 +0000722 !SK_(read_extra_suppression_info)(fd, buf, N_BUF, supp))
sewardjde4a1d02002-03-22 01:27:54 +0000723 goto syntax_error;
724
njn25e49d8e72002-09-23 09:36:25 +0000725 /* "i > 0" ensures at least one caller read. */
726 for (i = 0; i < VG_N_SUPP_CALLERS; i++) {
njn4ba5a792002-09-30 10:23:54 +0000727 eof = VG_(get_line) ( fd, buf, N_BUF );
sewardjde4a1d02002-03-22 01:27:54 +0000728 if (eof) goto syntax_error;
njn43c799e2003-04-08 00:08:52 +0000729 if (i > 0 && VG_STREQ(buf, "}"))
njn25e49d8e72002-09-23 09:36:25 +0000730 break;
731 supp->caller[i] = VG_(arena_strdup)(VG_AR_CORE, buf);
732 if (!setLocationTy(&(supp->caller[i]), &(supp->caller_ty[i])))
733 goto syntax_error;
sewardjde4a1d02002-03-22 01:27:54 +0000734 }
735
736 supp->next = vg_suppressions;
737 vg_suppressions = supp;
738 }
sewardjde4a1d02002-03-22 01:27:54 +0000739 VG_(close)(fd);
740 return;
741
742 syntax_error:
743 if (eof) {
744 VG_(message)(Vg_UserMsg,
745 "FATAL: in suppressions file `%s': unexpected EOF",
746 filename );
747 } else {
748 VG_(message)(Vg_UserMsg,
njn11cc9252002-10-07 14:42:59 +0000749 "FATAL: in suppressions file: `%s': syntax error on: %s",
sewardjde4a1d02002-03-22 01:27:54 +0000750 filename, buf );
751 }
752 VG_(close)(fd);
753 VG_(message)(Vg_UserMsg, "exiting now.");
754 VG_(exit)(1);
755
756# undef N_BUF
757}
758
759
760void VG_(load_suppressions) ( void )
761{
762 Int i;
763 vg_suppressions = NULL;
764 for (i = 0; i < VG_(clo_n_suppressions); i++) {
765 if (VG_(clo_verbosity) > 1) {
766 VG_(message)(Vg_UserMsg, "Reading suppressions file: %s",
767 VG_(clo_suppressions)[i] );
768 }
769 load_one_suppressions_file( VG_(clo_suppressions)[i] );
770 }
771}
772
njn25e49d8e72002-09-23 09:36:25 +0000773/* Return the name of an erring fn in a way which is useful
774 for comparing against the contents of a suppressions file.
775 Doesn't demangle the fn name, because we want to refer to
776 mangled names in the suppressions file.
sewardj99aac972002-12-26 01:53:45 +0000777*/
njn43c799e2003-04-08 00:08:52 +0000778static void get_objname_fnname ( Addr a, Char* obj_buf, Int n_obj_buf,
779 Char* fun_buf, Int n_fun_buf )
njn25e49d8e72002-09-23 09:36:25 +0000780{
781 (void)VG_(get_objname) ( a, obj_buf, n_obj_buf );
782 (void)VG_(get_fnname_nodemangle)( a, fun_buf, n_fun_buf );
783}
784
785static __inline__
njn810086f2002-11-14 12:42:47 +0000786Bool supp_matches_error(Supp* su, Error* err)
njn25e49d8e72002-09-23 09:36:25 +0000787{
njn810086f2002-11-14 12:42:47 +0000788 switch (su->skind) {
njn25e49d8e72002-09-23 09:36:25 +0000789 case PThreadSupp:
njn810086f2002-11-14 12:42:47 +0000790 return (err->ekind == PThreadErr);
njn25e49d8e72002-09-23 09:36:25 +0000791 default:
792 if (VG_(needs).skin_errors) {
njn810086f2002-11-14 12:42:47 +0000793 return SK_(error_matches_suppression)(err, su);
njn25e49d8e72002-09-23 09:36:25 +0000794 } else {
795 VG_(printf)(
796 "\nUnhandled suppression type: %u. VG_(needs).skin_errors\n"
797 "probably needs to be set.\n",
njn810086f2002-11-14 12:42:47 +0000798 err->ekind);
njne427a662002-10-02 11:08:25 +0000799 VG_(skin_panic)("unhandled suppression type");
njn25e49d8e72002-09-23 09:36:25 +0000800 }
801 }
802}
803
804static __inline__
njn810086f2002-11-14 12:42:47 +0000805Bool supp_matches_callers(Supp* su, Char caller_obj[][M_VG_ERRTXT],
806 Char caller_fun[][M_VG_ERRTXT])
njn25e49d8e72002-09-23 09:36:25 +0000807{
808 Int i;
809
810 for (i = 0; su->caller[i] != NULL; i++) {
811 switch (su->caller_ty[i]) {
njn4ba5a792002-09-30 10:23:54 +0000812 case ObjName: if (VG_(string_match)(su->caller[i],
813 caller_obj[i])) break;
njn25e49d8e72002-09-23 09:36:25 +0000814 return False;
njn4ba5a792002-09-30 10:23:54 +0000815 case FunName: if (VG_(string_match)(su->caller[i],
816 caller_fun[i])) break;
njn25e49d8e72002-09-23 09:36:25 +0000817 return False;
njn43c799e2003-04-08 00:08:52 +0000818 default: VG_(skin_panic)("supp_matches_callers");
njn25e49d8e72002-09-23 09:36:25 +0000819 }
820 }
821
822 /* If we reach here, it's a match */
823 return True;
824}
sewardjde4a1d02002-03-22 01:27:54 +0000825
njn810086f2002-11-14 12:42:47 +0000826/* Does an error context match a suppression? ie is this a suppressible
827 error? If so, return a pointer to the Supp record, otherwise NULL.
njn25e49d8e72002-09-23 09:36:25 +0000828 Tries to minimise the number of symbol searches since they are expensive.
sewardjde4a1d02002-03-22 01:27:54 +0000829*/
njn810086f2002-11-14 12:42:47 +0000830static Supp* is_suppressible_error ( Error* err )
sewardjde4a1d02002-03-22 01:27:54 +0000831{
njn25e49d8e72002-09-23 09:36:25 +0000832 Int i;
sewardjde4a1d02002-03-22 01:27:54 +0000833
njn25e49d8e72002-09-23 09:36:25 +0000834 Char caller_obj[VG_N_SUPP_CALLERS][M_VG_ERRTXT];
835 Char caller_fun[VG_N_SUPP_CALLERS][M_VG_ERRTXT];
sewardjde4a1d02002-03-22 01:27:54 +0000836
njn810086f2002-11-14 12:42:47 +0000837 Supp* su;
sewardjde4a1d02002-03-22 01:27:54 +0000838
njn25e49d8e72002-09-23 09:36:25 +0000839 /* get_objname_fnname() writes the function name and object name if
njn43c799e2003-04-08 00:08:52 +0000840 it finds them in the debug info. So the strings in the suppression
njn25e49d8e72002-09-23 09:36:25 +0000841 file should match these.
sewardjde4a1d02002-03-22 01:27:54 +0000842 */
843
844 /* Initialise these strs so they are always safe to compare, even
njn25e49d8e72002-09-23 09:36:25 +0000845 if get_objname_fnname doesn't write anything to them. */
846 for (i = 0; i < VG_N_SUPP_CALLERS; i++)
847 caller_obj[i][0] = caller_fun[i][0] = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000848
njn25e49d8e72002-09-23 09:36:25 +0000849 for (i = 0; i < VG_N_SUPP_CALLERS && i < VG_(clo_backtrace_size); i++) {
njn43c799e2003-04-08 00:08:52 +0000850 get_objname_fnname ( err->where->eips[i], caller_obj[i], M_VG_ERRTXT,
851 caller_fun[i], M_VG_ERRTXT );
sewardjde4a1d02002-03-22 01:27:54 +0000852 }
853
854 /* See if the error context matches any suppression. */
855 for (su = vg_suppressions; su != NULL; su = su->next) {
njn25e49d8e72002-09-23 09:36:25 +0000856 if (supp_matches_error(su, err) &&
857 supp_matches_callers(su, caller_obj, caller_fun)) {
858 return su;
sewardjde4a1d02002-03-22 01:27:54 +0000859 }
sewardjde4a1d02002-03-22 01:27:54 +0000860 }
njn25e49d8e72002-09-23 09:36:25 +0000861 return NULL; /* no matches */
sewardjde4a1d02002-03-22 01:27:54 +0000862}
863
sewardjde4a1d02002-03-22 01:27:54 +0000864/*--------------------------------------------------------------------*/
865/*--- end vg_errcontext.c ---*/
866/*--------------------------------------------------------------------*/