blob: 8de283abc04e05e751d10691e6a18b8a858e0d60 [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
njn3e884182003-04-15 13:03:23 +0000164 need in order to attach GDB are picked up out of VG_(baseBlock) rather
165 than from the thread table (vg_threads in vg_scheduler.c).
njn25e49d8e72002-09-23 09:36:25 +0000166
167 - If not from generated code but in response to requests passed back to
168 the scheduler (tst != NULL), we pick up %EIP/%EBP values from the
169 stored thread state, not from VG_(baseBlock).
170*/
171static __inline__
njn43c799e2003-04-08 00:08:52 +0000172void construct_error ( Error* err, ThreadState* tst, ErrorKind ekind, Addr a,
njn3e884182003-04-15 13:03:23 +0000173 Char* s, void* extra, ExeContext* where,
174 /*out*/Addr* m_eip, /*out*/Addr* m_esp,
175 /*out*/Addr* m_ebp )
sewardjde4a1d02002-03-22 01:27:54 +0000176{
njn810086f2002-11-14 12:42:47 +0000177 /* Core-only parts */
njn25e49d8e72002-09-23 09:36:25 +0000178 err->next = NULL;
179 err->supp = NULL;
180 err->count = 1;
njn43c799e2003-04-08 00:08:52 +0000181 if (NULL == where)
182 err->where = VG_(get_ExeContext)( tst );
183 else
184 err->where = where;
njn1d6c4bc2002-11-21 13:38:08 +0000185
njn25e49d8e72002-09-23 09:36:25 +0000186 if (NULL == tst) {
187 err->tid = VG_(get_current_tid)();
njn3e884182003-04-15 13:03:23 +0000188 *m_eip = VG_(baseBlock)[VGOFF_(m_eip)];
189 *m_esp = VG_(baseBlock)[VGOFF_(m_esp)];
190 *m_ebp = VG_(baseBlock)[VGOFF_(m_ebp)];
njn25e49d8e72002-09-23 09:36:25 +0000191 } else {
njn25e49d8e72002-09-23 09:36:25 +0000192 err->tid = tst->tid;
njn3e884182003-04-15 13:03:23 +0000193 *m_eip = tst->m_eip;
194 *m_esp = tst->m_esp;
195 *m_ebp = tst->m_ebp;
njn25e49d8e72002-09-23 09:36:25 +0000196 }
197
njn810086f2002-11-14 12:42:47 +0000198 /* Skin-relevant parts */
199 err->ekind = ekind;
200 err->addr = a;
201 err->string = s;
202 err->extra = extra;
njn25e49d8e72002-09-23 09:36:25 +0000203
204 /* sanity... */
205 vg_assert(err->tid >= 0 && err->tid < VG_N_THREADS);
206}
207
njn43c799e2003-04-08 00:08:52 +0000208void VG_(gen_suppression)(Error* err)
209{
210 UInt i;
211 UChar buf[M_VG_ERRTXT];
212 ExeContext* ec = VG_(get_error_where)(err);
213 Int stop_at = VG_(clo_backtrace_size);
214 Char* name = SK_(get_error_name)(err);
215
216 if (NULL == name) {
217 VG_(message)(Vg_UserMsg, "(skin does not allow error to be suppressed)");
218 return;
219 }
220
221 if (stop_at > 3) stop_at = 3; /* At most three names */
222 vg_assert(stop_at > 0);
223
224 VG_(printf)("{\n");
225 VG_(printf)(" <insert a suppression name here>\n");
226 VG_(printf)(" %s:%s\n", VG_(details).name, name);
227 SK_(print_extra_suppression_info)(err);
228
229 /* This loop condensed from VG_(mini_stack_dump)() */
230 i = 0;
231 do {
232 Addr eip = ec->eips[i];
233 if (i > 0)
234 eip--; /* point to calling line */
235
236 if ( VG_(get_fnname_nodemangle) (eip, buf, M_VG_ERRTXT) ) {
237 VG_(printf)(" fun:%s\n", buf);
238 } else if ( VG_(get_objname)(eip, buf, M_VG_ERRTXT) ) {
239 VG_(printf)(" obj:%s\n", buf);
240 } else {
241 VG_(printf)(" ???:??? "
242 "# unknown, suppression will not work, sorry)\n");
243 }
244 i++;
245 } while (i < stop_at && ec->eips[i] != 0);
246
247 VG_(printf)("}\n");
248}
249
njnb4aee052003-04-15 14:09:58 +0000250static
njn3e884182003-04-15 13:03:23 +0000251void do_actions_on_error(Error* err, Bool allow_GDB_attach,
252 Addr m_eip, Addr m_esp, Addr m_ebp )
njn43c799e2003-04-08 00:08:52 +0000253{
254 /* Perhaps we want a GDB attach at this point? */
njn3e884182003-04-15 13:03:23 +0000255 if (allow_GDB_attach &&
256 VG_(is_action_requested)( "Attach to GDB", & VG_(clo_GDB_attach) ))
257 {
258 VG_(swizzle_esp_then_start_GDB)( m_eip, m_esp, m_ebp );
njn43c799e2003-04-08 00:08:52 +0000259 }
260 /* Or maybe we want to generate the error's suppression? */
261 if (VG_(is_action_requested)( "Print suppression",
262 & VG_(clo_gen_suppressions) )) {
263 VG_(gen_suppression)(err);
264 }
265}
266
267/* Shared between VG_(maybe_record_error)() and VG_(unique_error)(),
268 just for pretty printing purposes. */
269static Bool is_first_shown_context = True;
270
njn25e49d8e72002-09-23 09:36:25 +0000271/* Top-level entry point to the error management subsystem.
272 All detected errors are notified here; this routine decides if/when the
273 user should see the error. */
274void VG_(maybe_record_error) ( ThreadState* tst,
275 ErrorKind ekind, Addr a, Char* s, void* extra )
276{
njn3e884182003-04-15 13:03:23 +0000277 Addr m_eip, m_esp, m_ebp;
njn810086f2002-11-14 12:42:47 +0000278 Error err;
279 Error* p;
280 Error* p_prev;
njn43c799e2003-04-08 00:08:52 +0000281 UInt extra_size;
njn810086f2002-11-14 12:42:47 +0000282 VgRes exe_res = Vg_MedRes;
njn810086f2002-11-14 12:42:47 +0000283 static Bool stopping_message = False;
284 static Bool slowdown_message = False;
285 static Int vg_n_errs_shown = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000286
sewardjf2537be2002-04-24 21:03:47 +0000287 /* After M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN different errors have
288 been found, or M_VG_COLLECT_NO_ERRORS_AFTER_FOUND total errors
289 have been found, just refuse to collect any more. This stops
290 the burden of the error-management system becoming excessive in
291 extremely buggy programs, although it does make it pretty
292 pointless to continue the Valgrind run after this point. */
sewardj2e432902002-06-13 20:44:00 +0000293 if (VG_(clo_error_limit)
sewardj72f98ff2002-06-13 17:23:38 +0000294 && (vg_n_errs_shown >= M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN
295 || vg_n_errs_found >= M_VG_COLLECT_NO_ERRORS_AFTER_FOUND)) {
sewardjde4a1d02002-03-22 01:27:54 +0000296 if (!stopping_message) {
297 VG_(message)(Vg_UserMsg, "");
sewardjf2537be2002-04-24 21:03:47 +0000298
299 if (vg_n_errs_shown >= M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN) {
300 VG_(message)(Vg_UserMsg,
301 "More than %d different errors detected. "
302 "I'm not reporting any more.",
303 M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN );
304 } else {
305 VG_(message)(Vg_UserMsg,
306 "More than %d total errors detected. "
307 "I'm not reporting any more.",
308 M_VG_COLLECT_NO_ERRORS_AFTER_FOUND );
309 }
310
sewardjde4a1d02002-03-22 01:27:54 +0000311 VG_(message)(Vg_UserMsg,
sewardjf2537be2002-04-24 21:03:47 +0000312 "Final error counts will be inaccurate. Go fix your program!");
sewardj72f98ff2002-06-13 17:23:38 +0000313 VG_(message)(Vg_UserMsg,
sewardj2e432902002-06-13 20:44:00 +0000314 "Rerun with --error-limit=no to disable this cutoff. Note");
sewardj72f98ff2002-06-13 17:23:38 +0000315 VG_(message)(Vg_UserMsg,
njn25e49d8e72002-09-23 09:36:25 +0000316 "that errors may occur in your program without prior warning from");
sewardj72f98ff2002-06-13 17:23:38 +0000317 VG_(message)(Vg_UserMsg,
318 "Valgrind, because errors are no longer being displayed.");
sewardjde4a1d02002-03-22 01:27:54 +0000319 VG_(message)(Vg_UserMsg, "");
320 stopping_message = True;
321 }
322 return;
323 }
324
325 /* After M_VG_COLLECT_ERRORS_SLOWLY_AFTER different errors have
326 been found, be much more conservative about collecting new
327 ones. */
328 if (vg_n_errs_shown >= M_VG_COLLECT_ERRORS_SLOWLY_AFTER) {
njn25e49d8e72002-09-23 09:36:25 +0000329 exe_res = Vg_LowRes;
sewardjde4a1d02002-03-22 01:27:54 +0000330 if (!slowdown_message) {
331 VG_(message)(Vg_UserMsg, "");
332 VG_(message)(Vg_UserMsg,
333 "More than %d errors detected. Subsequent errors",
334 M_VG_COLLECT_ERRORS_SLOWLY_AFTER);
335 VG_(message)(Vg_UserMsg,
336 "will still be recorded, but in less detail than before.");
337 slowdown_message = True;
338 }
339 }
340
njn25e49d8e72002-09-23 09:36:25 +0000341 /* Build ourselves the error */
njn3e884182003-04-15 13:03:23 +0000342 construct_error ( &err, tst, ekind, a, s, extra, NULL,
343 &m_eip, &m_esp, &m_ebp );
sewardjde4a1d02002-03-22 01:27:54 +0000344
345 /* First, see if we've got an error record matching this one. */
njn25e49d8e72002-09-23 09:36:25 +0000346 p = vg_errors;
sewardjde4a1d02002-03-22 01:27:54 +0000347 p_prev = NULL;
348 while (p != NULL) {
njn810086f2002-11-14 12:42:47 +0000349 if (eq_Error(exe_res, p, &err)) {
sewardjde4a1d02002-03-22 01:27:54 +0000350 /* Found it. */
351 p->count++;
352 if (p->supp != NULL) {
353 /* Deal correctly with suppressed errors. */
354 p->supp->count++;
355 vg_n_errs_suppressed++;
356 } else {
357 vg_n_errs_found++;
358 }
359
360 /* Move p to the front of the list so that future searches
361 for it are faster. */
362 if (p_prev != NULL) {
363 vg_assert(p_prev->next == p);
364 p_prev->next = p->next;
njn25e49d8e72002-09-23 09:36:25 +0000365 p->next = vg_errors;
366 vg_errors = p;
sewardjde4a1d02002-03-22 01:27:54 +0000367 }
368 return;
369 }
370 p_prev = p;
371 p = p->next;
372 }
373
374 /* Didn't see it. Copy and add. */
375
njn43c799e2003-04-08 00:08:52 +0000376 /* OK, we're really going to collect it. The context is on the stack and
377 will disappear shortly, so we must copy it. First do the main
378 (non-`extra') part.
njn25e49d8e72002-09-23 09:36:25 +0000379
njn43c799e2003-04-08 00:08:52 +0000380 Then SK_(update_extra) can update the `extra' part. This is for when
381 there are more details to fill in which take time to work out but
382 don't affect our earlier decision to include the error -- by
njn25e49d8e72002-09-23 09:36:25 +0000383 postponing those details until now, we avoid the extra work in the
njn810086f2002-11-14 12:42:47 +0000384 case where we ignore the error. Ugly.
njn43c799e2003-04-08 00:08:52 +0000385
386 Then, if there is an `extra' part, copy it too, using the size that
387 SK_(update_extra) returned.
388 */
389
390 /* copy main part */
njn810086f2002-11-14 12:42:47 +0000391 p = VG_(arena_malloc)(VG_AR_ERRORS, sizeof(Error));
njn25e49d8e72002-09-23 09:36:25 +0000392 *p = err;
njn43c799e2003-04-08 00:08:52 +0000393
394 /* update `extra' */
395 extra_size = SK_(update_extra)(p);
396
397 /* copy `extra' if there is one */
398 if (NULL != p->extra) {
399 void* new_extra = VG_(malloc)(extra_size);
400 VG_(memcpy)(new_extra, p->extra, extra_size);
401 p->extra = new_extra;
402 }
403
njn25e49d8e72002-09-23 09:36:25 +0000404 p->next = vg_errors;
405 p->supp = is_suppressible_error(&err);
406 vg_errors = p;
sewardjde4a1d02002-03-22 01:27:54 +0000407 if (p->supp == NULL) {
408 vg_n_errs_found++;
409 if (!is_first_shown_context)
410 VG_(message)(Vg_UserMsg, "");
njn43c799e2003-04-08 00:08:52 +0000411 pp_Error(p, False);
sewardjde4a1d02002-03-22 01:27:54 +0000412 is_first_shown_context = False;
413 vg_n_errs_shown++;
njn3e884182003-04-15 13:03:23 +0000414 do_actions_on_error(p, /*allow_GDB_attach*/True, m_eip, m_esp, m_ebp );
sewardjde4a1d02002-03-22 01:27:54 +0000415 } else {
416 vg_n_errs_suppressed++;
417 p->supp->count++;
418 }
419}
420
njn43c799e2003-04-08 00:08:52 +0000421/* Second top-level entry point to the error management subsystem, for
422 errors that the skin want to report immediately, eg. because they're
423 guaranteed to only happen once. This avoids all the recording and
424 comparing stuff. But they can be suppressed; returns True if it is
425 suppressed. Bool `print_error' dictates whether to print the error. */
426Bool VG_(unique_error) ( ThreadState* tst, ErrorKind ekind, Addr a, Char* s,
njn3e884182003-04-15 13:03:23 +0000427 void* extra, ExeContext* where, Bool print_error,
428 Bool allow_GDB_attach )
njn43c799e2003-04-08 00:08:52 +0000429{
430 Error err;
njn3e884182003-04-15 13:03:23 +0000431 Addr m_eip, m_esp, m_ebp;
njn43c799e2003-04-08 00:08:52 +0000432
433 /* Build ourselves the error */
njn3e884182003-04-15 13:03:23 +0000434 construct_error ( &err, tst, ekind, a, s, extra, where,
435 &m_eip, &m_esp, &m_ebp );
njn43c799e2003-04-08 00:08:52 +0000436
437 /* Unless it's suppressed, we're going to show it. Don't need to make
438 a copy, because it's only temporary anyway.
439
440 Then update the `extra' part with SK_(update_extra), because that can
441 have an affect on whether it's suppressed. Ignore the size return
442 value of SK_(update_extra), because we're not copying `extra'. */
443 (void)SK_(update_extra)(&err);
444
445 if (NULL == is_suppressible_error(&err)) {
446 vg_n_errs_found++;
447
448 if (print_error) {
449 if (!is_first_shown_context)
450 VG_(message)(Vg_UserMsg, "");
451 pp_Error(&err, False);
452 is_first_shown_context = False;
453 }
njn3e884182003-04-15 13:03:23 +0000454 do_actions_on_error(&err, allow_GDB_attach, m_eip, m_esp, m_ebp);
njn43c799e2003-04-08 00:08:52 +0000455
456 return False;
457
458 } else {
459 vg_n_errs_suppressed++;
460 return True;
461 }
462}
463
sewardjde4a1d02002-03-22 01:27:54 +0000464
sewardjde4a1d02002-03-22 01:27:54 +0000465/*------------------------------------------------------------*/
466/*--- Exported fns ---*/
467/*------------------------------------------------------------*/
468
njn25e49d8e72002-09-23 09:36:25 +0000469/* These are called not from generated code but from the scheduler */
sewardj8c824512002-04-14 04:16:48 +0000470
njn25e49d8e72002-09-23 09:36:25 +0000471void VG_(record_pthread_error) ( ThreadId tid, Char* msg )
sewardjde4a1d02002-03-22 01:27:54 +0000472{
njn25e49d8e72002-09-23 09:36:25 +0000473 if (! VG_(needs).core_errors) return;
474 VG_(maybe_record_error)( &VG_(threads)[tid], PThreadErr, /*addr*/0, msg,
475 /*extra*/NULL );
sewardjde4a1d02002-03-22 01:27:54 +0000476}
477
sewardj8c824512002-04-14 04:16:48 +0000478/*------------------------------*/
479
sewardjde4a1d02002-03-22 01:27:54 +0000480void VG_(show_all_errors) ( void )
481{
njn810086f2002-11-14 12:42:47 +0000482 Int i, n_min;
483 Int n_err_contexts, n_supp_contexts;
484 Error *p, *p_min;
485 Supp *su;
486 Bool any_supp;
sewardjde4a1d02002-03-22 01:27:54 +0000487
488 if (VG_(clo_verbosity) == 0)
489 return;
490
491 n_err_contexts = 0;
njn25e49d8e72002-09-23 09:36:25 +0000492 for (p = vg_errors; p != NULL; p = p->next) {
sewardjde4a1d02002-03-22 01:27:54 +0000493 if (p->supp == NULL)
494 n_err_contexts++;
495 }
496
497 n_supp_contexts = 0;
498 for (su = vg_suppressions; su != NULL; su = su->next) {
499 if (su->count > 0)
500 n_supp_contexts++;
501 }
sewardjde4a1d02002-03-22 01:27:54 +0000502 VG_(message)(Vg_UserMsg,
503 "ERROR SUMMARY: "
504 "%d errors from %d contexts (suppressed: %d from %d)",
505 vg_n_errs_found, n_err_contexts,
506 vg_n_errs_suppressed, n_supp_contexts );
507
508 if (VG_(clo_verbosity) <= 1)
509 return;
510
511 /* Print the contexts in order of increasing error count. */
512 for (i = 0; i < n_err_contexts; i++) {
513 n_min = (1 << 30) - 1;
514 p_min = NULL;
njn25e49d8e72002-09-23 09:36:25 +0000515 for (p = vg_errors; p != NULL; p = p->next) {
sewardjde4a1d02002-03-22 01:27:54 +0000516 if (p->supp != NULL) continue;
517 if (p->count < n_min) {
518 n_min = p->count;
519 p_min = p;
520 }
521 }
njne427a662002-10-02 11:08:25 +0000522 if (p_min == NULL) VG_(skin_panic)("show_all_errors()");
sewardjde4a1d02002-03-22 01:27:54 +0000523
524 VG_(message)(Vg_UserMsg, "");
525 VG_(message)(Vg_UserMsg, "%d errors in context %d of %d:",
526 p_min->count,
527 i+1, n_err_contexts);
njn810086f2002-11-14 12:42:47 +0000528 pp_Error( p_min, False );
sewardjde4a1d02002-03-22 01:27:54 +0000529
530 if ((i+1 == VG_(clo_dump_error))) {
sewardj1e8cdc92002-04-18 11:37:52 +0000531 VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to below NULLs */,
sewardj22854b92002-11-30 14:00:47 +0000532 p_min->where->eips[0], NULL, NULL, NULL, NULL );
sewardjde4a1d02002-03-22 01:27:54 +0000533 }
534
535 p_min->count = 1 << 30;
536 }
537
538 if (n_supp_contexts > 0)
539 VG_(message)(Vg_DebugMsg, "");
540 any_supp = False;
541 for (su = vg_suppressions; su != NULL; su = su->next) {
542 if (su->count > 0) {
543 any_supp = True;
njn25e49d8e72002-09-23 09:36:25 +0000544 VG_(message)(Vg_DebugMsg, "supp: %4d %s", su->count, su->sname);
sewardjde4a1d02002-03-22 01:27:54 +0000545 }
546 }
547
548 if (n_err_contexts > 0) {
549 if (any_supp)
550 VG_(message)(Vg_UserMsg, "");
551 VG_(message)(Vg_UserMsg,
552 "IN SUMMARY: "
553 "%d errors from %d contexts (suppressed: %d from %d)",
554 vg_n_errs_found, n_err_contexts,
555 vg_n_errs_suppressed,
556 n_supp_contexts );
557 VG_(message)(Vg_UserMsg, "");
558 }
559}
560
561/*------------------------------------------------------------*/
562/*--- Standard suppressions ---*/
563/*------------------------------------------------------------*/
564
565/* Get a non-blank, non-comment line of at most nBuf chars from fd.
566 Skips leading spaces on the line. Return True if EOF was hit instead.
567*/
568
569#define VG_ISSPACE(ch) (((ch)==' ') || ((ch)=='\n') || ((ch)=='\t'))
570
njn4ba5a792002-09-30 10:23:54 +0000571Bool VG_(get_line) ( Int fd, Char* buf, Int nBuf )
sewardjde4a1d02002-03-22 01:27:54 +0000572{
573 Char ch;
574 Int n, i;
575 while (True) {
576 /* First, read until a non-blank char appears. */
577 while (True) {
578 n = VG_(read)(fd, &ch, 1);
579 if (n == 1 && !VG_ISSPACE(ch)) break;
580 if (n == 0) return True;
581 }
582
583 /* Now, read the line into buf. */
584 i = 0;
585 buf[i++] = ch; buf[i] = 0;
586 while (True) {
587 n = VG_(read)(fd, &ch, 1);
588 if (n == 0) return False; /* the next call will return True */
589 if (ch == '\n') break;
590 if (i > 0 && i == nBuf-1) i--;
591 buf[i++] = ch; buf[i] = 0;
592 }
593 while (i > 1 && VG_ISSPACE(buf[i-1])) {
594 i--; buf[i] = 0;
595 };
596
597 /* VG_(printf)("The line is `%s'\n", buf); */
598 /* Ok, we have a line. If a non-comment line, return.
599 If a comment line, start all over again. */
600 if (buf[0] != '#') return False;
601 }
602}
603
604
605/* *p_caller contains the raw name of a caller, supposedly either
606 fun:some_function_name or
607 obj:some_object_name.
608 Set *p_ty accordingly and advance *p_caller over the descriptor
609 (fun: or obj:) part.
610 Returns False if failed.
611*/
njn25e49d8e72002-09-23 09:36:25 +0000612static Bool setLocationTy ( Char** p_caller, SuppLocTy* p_ty )
sewardjde4a1d02002-03-22 01:27:54 +0000613{
614 if (VG_(strncmp)(*p_caller, "fun:", 4) == 0) {
615 (*p_caller) += 4;
616 *p_ty = FunName;
617 return True;
618 }
619 if (VG_(strncmp)(*p_caller, "obj:", 4) == 0) {
620 (*p_caller) += 4;
621 *p_ty = ObjName;
622 return True;
623 }
624 VG_(printf)("location should start with fun: or obj:\n");
625 return False;
626}
627
628
njn11cc9252002-10-07 14:42:59 +0000629/* Look for "skin" in a string like "skin1,skin2,skin3" */
630static __inline__
631Bool skin_name_present(Char *name, Char *names)
632{
633 Bool found;
634 Char *s = NULL; /* Shut gcc up */
635 Int len = VG_(strlen)(name);
636
637 found = (NULL != (s = VG_(strstr)(names, name)) &&
638 (s == names || *(s-1) == ',') &&
639 (*(s+len) == ',' || *(s+len) == '\0')
640 );
641
642 return found;
643}
644
sewardjde4a1d02002-03-22 01:27:54 +0000645/* Read suppressions from the file specified in vg_clo_suppressions
646 and place them in the suppressions list. If there's any difficulty
647 doing this, just give up -- there's no point in trying to recover.
648*/
sewardjde4a1d02002-03-22 01:27:54 +0000649static void load_one_suppressions_file ( Char* filename )
650{
651# define N_BUF 200
njnc40c3a82002-10-02 11:02:27 +0000652 Int fd, i;
653 Bool eof;
654 Char buf[N_BUF+1];
njn11cc9252002-10-07 14:42:59 +0000655 Char* skin_names;
njnc40c3a82002-10-02 11:02:27 +0000656 Char* supp_name;
657
njn25e49d8e72002-09-23 09:36:25 +0000658 fd = VG_(open)( filename, VKI_O_RDONLY, 0 );
sewardjde4a1d02002-03-22 01:27:54 +0000659 if (fd == -1) {
njn25e49d8e72002-09-23 09:36:25 +0000660 VG_(message)(Vg_UserMsg, "FATAL: can't open suppressions file `%s'",
sewardjde4a1d02002-03-22 01:27:54 +0000661 filename );
662 VG_(exit)(1);
663 }
664
665 while (True) {
njn25e49d8e72002-09-23 09:36:25 +0000666 /* Assign and initialise the two suppression halves (core and skin) */
njn810086f2002-11-14 12:42:47 +0000667 Supp* supp;
668 supp = VG_(arena_malloc)(VG_AR_CORE, sizeof(Supp));
sewardjde4a1d02002-03-22 01:27:54 +0000669 supp->count = 0;
njn25e49d8e72002-09-23 09:36:25 +0000670 for (i = 0; i < VG_N_SUPP_CALLERS; i++) supp->caller[i] = NULL;
njn810086f2002-11-14 12:42:47 +0000671 supp->string = supp->extra = NULL;
sewardjde4a1d02002-03-22 01:27:54 +0000672
njn4ba5a792002-09-30 10:23:54 +0000673 eof = VG_(get_line) ( fd, buf, N_BUF );
sewardjde4a1d02002-03-22 01:27:54 +0000674 if (eof) break;
675
njn43c799e2003-04-08 00:08:52 +0000676 if (!VG_STREQ(buf, "{")) goto syntax_error;
sewardjde4a1d02002-03-22 01:27:54 +0000677
njn4ba5a792002-09-30 10:23:54 +0000678 eof = VG_(get_line) ( fd, buf, N_BUF );
njn43c799e2003-04-08 00:08:52 +0000679 if (eof || VG_STREQ(buf, "}")) goto syntax_error;
njn25e49d8e72002-09-23 09:36:25 +0000680 supp->sname = VG_(arena_strdup)(VG_AR_CORE, buf);
sewardjde4a1d02002-03-22 01:27:54 +0000681
njn4ba5a792002-09-30 10:23:54 +0000682 eof = VG_(get_line) ( fd, buf, N_BUF );
njn25e49d8e72002-09-23 09:36:25 +0000683
sewardjde4a1d02002-03-22 01:27:54 +0000684 if (eof) goto syntax_error;
sewardjde4a1d02002-03-22 01:27:54 +0000685
njn11cc9252002-10-07 14:42:59 +0000686 /* Check it has the "skin1,skin2,...:supp" form (look for ':') */
njnc40c3a82002-10-02 11:02:27 +0000687 i = 0;
688 while (True) {
689 if (buf[i] == ':') break;
690 if (buf[i] == '\0') goto syntax_error;
691 i++;
njn25e49d8e72002-09-23 09:36:25 +0000692 }
njnc40c3a82002-10-02 11:02:27 +0000693 buf[i] = '\0'; /* Replace ':', splitting into two strings */
694
njn11cc9252002-10-07 14:42:59 +0000695 skin_names = & buf[0];
696 supp_name = & buf[i+1];
njnc40c3a82002-10-02 11:02:27 +0000697
njn11cc9252002-10-07 14:42:59 +0000698 /* Is it a core suppression? */
699 if (VG_(needs).core_errors && skin_name_present("core", skin_names))
njnc40c3a82002-10-02 11:02:27 +0000700 {
njn43c799e2003-04-08 00:08:52 +0000701 if (VG_STREQ(supp_name, "PThread"))
njn810086f2002-11-14 12:42:47 +0000702 supp->skind = PThreadSupp;
njnc40c3a82002-10-02 11:02:27 +0000703 else
704 goto syntax_error;
705 }
706
njn11cc9252002-10-07 14:42:59 +0000707 /* Is it a skin suppression? */
708 else if (VG_(needs).skin_errors &&
709 skin_name_present(VG_(details).name, skin_names))
njnc40c3a82002-10-02 11:02:27 +0000710 {
njn810086f2002-11-14 12:42:47 +0000711 if (SK_(recognised_suppression)(supp_name, supp))
njnc40c3a82002-10-02 11:02:27 +0000712 {
njn810086f2002-11-14 12:42:47 +0000713 /* Do nothing, function fills in supp->skind */
njnc40c3a82002-10-02 11:02:27 +0000714 } else
715 goto syntax_error;
716 }
717
njn25e49d8e72002-09-23 09:36:25 +0000718 else {
njnc40c3a82002-10-02 11:02:27 +0000719 /* Ignore rest of suppression */
njn25e49d8e72002-09-23 09:36:25 +0000720 while (True) {
njn4ba5a792002-09-30 10:23:54 +0000721 eof = VG_(get_line) ( fd, buf, N_BUF );
njn25e49d8e72002-09-23 09:36:25 +0000722 if (eof) goto syntax_error;
njn43c799e2003-04-08 00:08:52 +0000723 if (VG_STREQ(buf, "}"))
njn25e49d8e72002-09-23 09:36:25 +0000724 break;
725 }
726 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000727 }
728
njn25e49d8e72002-09-23 09:36:25 +0000729 if (VG_(needs).skin_errors &&
njn810086f2002-11-14 12:42:47 +0000730 !SK_(read_extra_suppression_info)(fd, buf, N_BUF, supp))
sewardjde4a1d02002-03-22 01:27:54 +0000731 goto syntax_error;
732
njn25e49d8e72002-09-23 09:36:25 +0000733 /* "i > 0" ensures at least one caller read. */
734 for (i = 0; i < VG_N_SUPP_CALLERS; i++) {
njn4ba5a792002-09-30 10:23:54 +0000735 eof = VG_(get_line) ( fd, buf, N_BUF );
sewardjde4a1d02002-03-22 01:27:54 +0000736 if (eof) goto syntax_error;
njn43c799e2003-04-08 00:08:52 +0000737 if (i > 0 && VG_STREQ(buf, "}"))
njn25e49d8e72002-09-23 09:36:25 +0000738 break;
739 supp->caller[i] = VG_(arena_strdup)(VG_AR_CORE, buf);
740 if (!setLocationTy(&(supp->caller[i]), &(supp->caller_ty[i])))
741 goto syntax_error;
sewardjde4a1d02002-03-22 01:27:54 +0000742 }
743
744 supp->next = vg_suppressions;
745 vg_suppressions = supp;
746 }
sewardjde4a1d02002-03-22 01:27:54 +0000747 VG_(close)(fd);
748 return;
749
750 syntax_error:
751 if (eof) {
752 VG_(message)(Vg_UserMsg,
753 "FATAL: in suppressions file `%s': unexpected EOF",
754 filename );
755 } else {
756 VG_(message)(Vg_UserMsg,
njn11cc9252002-10-07 14:42:59 +0000757 "FATAL: in suppressions file: `%s': syntax error on: %s",
sewardjde4a1d02002-03-22 01:27:54 +0000758 filename, buf );
759 }
760 VG_(close)(fd);
761 VG_(message)(Vg_UserMsg, "exiting now.");
762 VG_(exit)(1);
763
764# undef N_BUF
765}
766
767
768void VG_(load_suppressions) ( void )
769{
770 Int i;
771 vg_suppressions = NULL;
772 for (i = 0; i < VG_(clo_n_suppressions); i++) {
773 if (VG_(clo_verbosity) > 1) {
774 VG_(message)(Vg_UserMsg, "Reading suppressions file: %s",
775 VG_(clo_suppressions)[i] );
776 }
777 load_one_suppressions_file( VG_(clo_suppressions)[i] );
778 }
779}
780
njn25e49d8e72002-09-23 09:36:25 +0000781/* Return the name of an erring fn in a way which is useful
782 for comparing against the contents of a suppressions file.
783 Doesn't demangle the fn name, because we want to refer to
784 mangled names in the suppressions file.
sewardj99aac972002-12-26 01:53:45 +0000785*/
njn43c799e2003-04-08 00:08:52 +0000786static void get_objname_fnname ( Addr a, Char* obj_buf, Int n_obj_buf,
787 Char* fun_buf, Int n_fun_buf )
njn25e49d8e72002-09-23 09:36:25 +0000788{
789 (void)VG_(get_objname) ( a, obj_buf, n_obj_buf );
790 (void)VG_(get_fnname_nodemangle)( a, fun_buf, n_fun_buf );
791}
792
793static __inline__
njn810086f2002-11-14 12:42:47 +0000794Bool supp_matches_error(Supp* su, Error* err)
njn25e49d8e72002-09-23 09:36:25 +0000795{
njn810086f2002-11-14 12:42:47 +0000796 switch (su->skind) {
njn25e49d8e72002-09-23 09:36:25 +0000797 case PThreadSupp:
njn810086f2002-11-14 12:42:47 +0000798 return (err->ekind == PThreadErr);
njn25e49d8e72002-09-23 09:36:25 +0000799 default:
800 if (VG_(needs).skin_errors) {
njn810086f2002-11-14 12:42:47 +0000801 return SK_(error_matches_suppression)(err, su);
njn25e49d8e72002-09-23 09:36:25 +0000802 } else {
803 VG_(printf)(
804 "\nUnhandled suppression type: %u. VG_(needs).skin_errors\n"
805 "probably needs to be set.\n",
njn810086f2002-11-14 12:42:47 +0000806 err->ekind);
njne427a662002-10-02 11:08:25 +0000807 VG_(skin_panic)("unhandled suppression type");
njn25e49d8e72002-09-23 09:36:25 +0000808 }
809 }
810}
811
812static __inline__
njn810086f2002-11-14 12:42:47 +0000813Bool supp_matches_callers(Supp* su, Char caller_obj[][M_VG_ERRTXT],
814 Char caller_fun[][M_VG_ERRTXT])
njn25e49d8e72002-09-23 09:36:25 +0000815{
816 Int i;
817
818 for (i = 0; su->caller[i] != NULL; i++) {
819 switch (su->caller_ty[i]) {
njn4ba5a792002-09-30 10:23:54 +0000820 case ObjName: if (VG_(string_match)(su->caller[i],
821 caller_obj[i])) break;
njn25e49d8e72002-09-23 09:36:25 +0000822 return False;
njn4ba5a792002-09-30 10:23:54 +0000823 case FunName: if (VG_(string_match)(su->caller[i],
824 caller_fun[i])) break;
njn25e49d8e72002-09-23 09:36:25 +0000825 return False;
njn43c799e2003-04-08 00:08:52 +0000826 default: VG_(skin_panic)("supp_matches_callers");
njn25e49d8e72002-09-23 09:36:25 +0000827 }
828 }
829
830 /* If we reach here, it's a match */
831 return True;
832}
sewardjde4a1d02002-03-22 01:27:54 +0000833
njn810086f2002-11-14 12:42:47 +0000834/* Does an error context match a suppression? ie is this a suppressible
835 error? If so, return a pointer to the Supp record, otherwise NULL.
njn25e49d8e72002-09-23 09:36:25 +0000836 Tries to minimise the number of symbol searches since they are expensive.
sewardjde4a1d02002-03-22 01:27:54 +0000837*/
njn810086f2002-11-14 12:42:47 +0000838static Supp* is_suppressible_error ( Error* err )
sewardjde4a1d02002-03-22 01:27:54 +0000839{
njn25e49d8e72002-09-23 09:36:25 +0000840 Int i;
sewardjde4a1d02002-03-22 01:27:54 +0000841
njn25e49d8e72002-09-23 09:36:25 +0000842 Char caller_obj[VG_N_SUPP_CALLERS][M_VG_ERRTXT];
843 Char caller_fun[VG_N_SUPP_CALLERS][M_VG_ERRTXT];
sewardjde4a1d02002-03-22 01:27:54 +0000844
njn810086f2002-11-14 12:42:47 +0000845 Supp* su;
sewardjde4a1d02002-03-22 01:27:54 +0000846
njn25e49d8e72002-09-23 09:36:25 +0000847 /* get_objname_fnname() writes the function name and object name if
njn43c799e2003-04-08 00:08:52 +0000848 it finds them in the debug info. So the strings in the suppression
njn25e49d8e72002-09-23 09:36:25 +0000849 file should match these.
sewardjde4a1d02002-03-22 01:27:54 +0000850 */
851
852 /* Initialise these strs so they are always safe to compare, even
njn25e49d8e72002-09-23 09:36:25 +0000853 if get_objname_fnname doesn't write anything to them. */
854 for (i = 0; i < VG_N_SUPP_CALLERS; i++)
855 caller_obj[i][0] = caller_fun[i][0] = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000856
njn25e49d8e72002-09-23 09:36:25 +0000857 for (i = 0; i < VG_N_SUPP_CALLERS && i < VG_(clo_backtrace_size); i++) {
njn43c799e2003-04-08 00:08:52 +0000858 get_objname_fnname ( err->where->eips[i], caller_obj[i], M_VG_ERRTXT,
859 caller_fun[i], M_VG_ERRTXT );
sewardjde4a1d02002-03-22 01:27:54 +0000860 }
861
862 /* See if the error context matches any suppression. */
863 for (su = vg_suppressions; su != NULL; su = su->next) {
njn25e49d8e72002-09-23 09:36:25 +0000864 if (supp_matches_error(su, err) &&
865 supp_matches_callers(su, caller_obj, caller_fun)) {
866 return su;
sewardjde4a1d02002-03-22 01:27:54 +0000867 }
sewardjde4a1d02002-03-22 01:27:54 +0000868 }
njn25e49d8e72002-09-23 09:36:25 +0000869 return NULL; /* no matches */
sewardjde4a1d02002-03-22 01:27:54 +0000870}
871
sewardjde4a1d02002-03-22 01:27:54 +0000872/*--------------------------------------------------------------------*/
873/*--- end vg_errcontext.c ---*/
874/*--------------------------------------------------------------------*/