blob: ac7874b5d2b83ac6113f4d53533a92647ab0864f [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
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. */
njn25e49d8e72002-09-23 09:36:25 +000039static CoreError* vg_errors = NULL;
sewardjde4a1d02002-03-22 01:27:54 +000040
41/* The list of suppression directives, as read from the specified
42 suppressions file. */
njn25e49d8e72002-09-23 09:36:25 +000043static CoreSupp* vg_suppressions = NULL;
sewardjde4a1d02002-03-22 01:27:54 +000044
45/* Running count of unsuppressed errors detected. */
46static UInt vg_n_errs_found = 0;
47
48/* Running count of suppressed errors detected. */
49static UInt vg_n_errs_suppressed = 0;
50
51/* forwards ... */
njn25e49d8e72002-09-23 09:36:25 +000052static CoreSupp* is_suppressible_error ( CoreError* err );
sewardjde4a1d02002-03-22 01:27:54 +000053
54
55/*------------------------------------------------------------*/
56/*--- Helper fns ---*/
57/*------------------------------------------------------------*/
58
sewardjde4a1d02002-03-22 01:27:54 +000059/* Compare error contexts, to detect duplicates. Note that if they
60 are otherwise the same, the faulting addrs and associated rwoffsets
61 are allowed to be different. */
njn25e49d8e72002-09-23 09:36:25 +000062static Bool eq_CoreError ( VgRes res, CoreError* e1, CoreError* e2 )
sewardjde4a1d02002-03-22 01:27:54 +000063{
njn25e49d8e72002-09-23 09:36:25 +000064 if (e1->skin_err.ekind != e2->skin_err.ekind)
sewardjde4a1d02002-03-22 01:27:54 +000065 return False;
njn25e49d8e72002-09-23 09:36:25 +000066 if (!VG_(eq_ExeContext)(res, e1->where, e2->where))
sewardjde4a1d02002-03-22 01:27:54 +000067 return False;
68
njn25e49d8e72002-09-23 09:36:25 +000069 switch (e1->skin_err.ekind) {
sewardj4dced352002-06-04 22:54:20 +000070 case PThreadErr:
njn25e49d8e72002-09-23 09:36:25 +000071 vg_assert(VG_(needs).core_errors);
72 if (e1->skin_err.string == e2->skin_err.string)
sewardj4dced352002-06-04 22:54:20 +000073 return True;
njn25e49d8e72002-09-23 09:36:25 +000074 if (0 == VG_(strcmp)(e1->skin_err.string, e2->skin_err.string))
sewardj4dced352002-06-04 22:54:20 +000075 return True;
76 return False;
sewardjde4a1d02002-03-22 01:27:54 +000077 default:
njn25e49d8e72002-09-23 09:36:25 +000078 if (VG_(needs).skin_errors)
79 return SK_(eq_SkinError)(res, &e1->skin_err, &e2->skin_err);
80 else {
81 VG_(printf)("\nUnhandled error type: %u. VG_(needs).skin_errors\n"
82 "probably needs to be set.\n",
83 e1->skin_err.ekind);
84 VG_(skin_error)("unhandled error type");
85 }
sewardjde4a1d02002-03-22 01:27:54 +000086 }
87}
88
njn25e49d8e72002-09-23 09:36:25 +000089static void pp_CoreError ( CoreError* err, Bool printCount )
sewardjde4a1d02002-03-22 01:27:54 +000090{
njn25e49d8e72002-09-23 09:36:25 +000091 /* Closure for printing where the error occurred. Abstracts details
92 about the `where' field away from the skin. */
93 void pp_ExeContextClosure(void)
94 {
95 VG_(pp_ExeContext) ( err->where );
sewardjde4a1d02002-03-22 01:27:54 +000096 }
njn25e49d8e72002-09-23 09:36:25 +000097
sewardjde4a1d02002-03-22 01:27:54 +000098 if (printCount)
njn25e49d8e72002-09-23 09:36:25 +000099 VG_(message)(Vg_UserMsg, "Observed %d times:", err->count );
100 if (err->tid > 1)
101 VG_(message)(Vg_UserMsg, "Thread %d:", err->tid );
102
103 switch (err->skin_err.ekind) {
sewardj4dced352002-06-04 22:54:20 +0000104 case PThreadErr:
njn25e49d8e72002-09-23 09:36:25 +0000105 vg_assert(VG_(needs).core_errors);
106 VG_(message)(Vg_UserMsg, "%s", err->skin_err.string );
107 VG_(pp_ExeContext)(err->where);
sewardj4dced352002-06-04 22:54:20 +0000108 break;
sewardjde4a1d02002-03-22 01:27:54 +0000109 default:
njn25e49d8e72002-09-23 09:36:25 +0000110 if (VG_(needs).skin_errors)
111 SK_(pp_SkinError)( &err->skin_err, &pp_ExeContextClosure );
112 else {
113 VG_(printf)("\nUnhandled error type: %u. VG_(needs).skin_errors\n"
114 "probably needs to be set?\n",
115 err->skin_err.ekind);
116 VG_(skin_error)("unhandled error type");
117 }
sewardjde4a1d02002-03-22 01:27:54 +0000118 }
119}
120
sewardjde4a1d02002-03-22 01:27:54 +0000121/* Figure out if we want to attach for GDB for this error, possibly
122 by asking the user. */
123static
124Bool vg_is_GDB_attach_requested ( void )
125{
126 Char ch, ch2;
127 Int res;
128
129 if (VG_(clo_GDB_attach) == False)
130 return False;
131
132 VG_(message)(Vg_UserMsg, "");
133
134 again:
135 VG_(printf)(
136 "==%d== "
137 "---- Attach to GDB ? --- [Return/N/n/Y/y/C/c] ---- ",
138 VG_(getpid)()
139 );
140
141 res = VG_(read)(0 /*stdin*/, &ch, 1);
142 if (res != 1) goto ioerror;
143 /* res == 1 */
144 if (ch == '\n') return False;
145 if (ch != 'N' && ch != 'n' && ch != 'Y' && ch != 'y'
146 && ch != 'C' && ch != 'c') goto again;
147
148 res = VG_(read)(0 /*stdin*/, &ch2, 1);
149 if (res != 1) goto ioerror;
150 if (ch2 != '\n') goto again;
151
152 /* No, don't want to attach. */
153 if (ch == 'n' || ch == 'N') return False;
154 /* Yes, want to attach. */
155 if (ch == 'y' || ch == 'Y') return True;
156 /* No, don't want to attach, and don't ask again either. */
157 vg_assert(ch == 'c' || ch == 'C');
158
159 ioerror:
160 VG_(clo_GDB_attach) = False;
161 return False;
162}
163
164
njn25e49d8e72002-09-23 09:36:25 +0000165/* I've gone all object-oriented... initialisation depends on where the
166 error comes from:
167
168 - If from generated code (tst == NULL), the %EIP/%EBP values that we
169 need in order to create proper error messages are picked up out of
170 VG_(baseBlock) rather than from the thread table (vg_threads in
171 vg_scheduler.c).
172
173 - If not from generated code but in response to requests passed back to
174 the scheduler (tst != NULL), we pick up %EIP/%EBP values from the
175 stored thread state, not from VG_(baseBlock).
176*/
177static __inline__
178void construct_error ( CoreError* err, ThreadState* tst,
179 ErrorKind ekind, Addr a, Char* s, void* extra )
sewardjde4a1d02002-03-22 01:27:54 +0000180{
njn25e49d8e72002-09-23 09:36:25 +0000181 /* CoreError parts */
182 err->next = NULL;
183 err->supp = NULL;
184 err->count = 1;
185 if (NULL == tst) {
186 err->tid = VG_(get_current_tid)();
187 err->where =
188 VG_(get_ExeContext2)( VG_(baseBlock)[VGOFF_(m_eip)],
189 VG_(baseBlock)[VGOFF_(m_ebp)],
190 VG_(baseBlock)[VGOFF_(m_esp)],
191 VG_(threads)[err->tid].stack_highest_word);
192 err->m_eip = VG_(baseBlock)[VGOFF_(m_eip)];
193 err->m_esp = VG_(baseBlock)[VGOFF_(m_esp)];
194 err->m_ebp = VG_(baseBlock)[VGOFF_(m_ebp)];
195 } else {
196 err->where = VG_(get_ExeContext) ( tst );
197 err->tid = tst->tid;
198 err->m_eip = tst->m_eip;
199 err->m_esp = tst->m_esp;
200 err->m_ebp = tst->m_ebp;
201 }
202
203 /* SkinError parts */
204 err->skin_err.ekind = ekind;
205 err->skin_err.addr = a;
206 err->skin_err.string = s;
207 err->skin_err.extra = extra;
208
209 /* sanity... */
210 vg_assert(err->tid >= 0 && err->tid < VG_N_THREADS);
211}
212
213/* Top-level entry point to the error management subsystem.
214 All detected errors are notified here; this routine decides if/when the
215 user should see the error. */
216void VG_(maybe_record_error) ( ThreadState* tst,
217 ErrorKind ekind, Addr a, Char* s, void* extra )
218{
219 CoreError err;
220 CoreError* p;
221 CoreError* p_prev;
222 VgRes exe_res = Vg_MedRes;
sewardjde4a1d02002-03-22 01:27:54 +0000223 static Bool is_first_shown_context = True;
224 static Bool stopping_message = False;
225 static Bool slowdown_message = False;
226 static Int vg_n_errs_shown = 0;
227
sewardjf2537be2002-04-24 21:03:47 +0000228 /* After M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN different errors have
229 been found, or M_VG_COLLECT_NO_ERRORS_AFTER_FOUND total errors
230 have been found, just refuse to collect any more. This stops
231 the burden of the error-management system becoming excessive in
232 extremely buggy programs, although it does make it pretty
233 pointless to continue the Valgrind run after this point. */
sewardj2e432902002-06-13 20:44:00 +0000234 if (VG_(clo_error_limit)
sewardj72f98ff2002-06-13 17:23:38 +0000235 && (vg_n_errs_shown >= M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN
236 || vg_n_errs_found >= M_VG_COLLECT_NO_ERRORS_AFTER_FOUND)) {
sewardjde4a1d02002-03-22 01:27:54 +0000237 if (!stopping_message) {
238 VG_(message)(Vg_UserMsg, "");
sewardjf2537be2002-04-24 21:03:47 +0000239
240 if (vg_n_errs_shown >= M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN) {
241 VG_(message)(Vg_UserMsg,
242 "More than %d different errors detected. "
243 "I'm not reporting any more.",
244 M_VG_COLLECT_NO_ERRORS_AFTER_SHOWN );
245 } else {
246 VG_(message)(Vg_UserMsg,
247 "More than %d total errors detected. "
248 "I'm not reporting any more.",
249 M_VG_COLLECT_NO_ERRORS_AFTER_FOUND );
250 }
251
sewardjde4a1d02002-03-22 01:27:54 +0000252 VG_(message)(Vg_UserMsg,
sewardjf2537be2002-04-24 21:03:47 +0000253 "Final error counts will be inaccurate. Go fix your program!");
sewardj72f98ff2002-06-13 17:23:38 +0000254 VG_(message)(Vg_UserMsg,
sewardj2e432902002-06-13 20:44:00 +0000255 "Rerun with --error-limit=no to disable this cutoff. Note");
sewardj72f98ff2002-06-13 17:23:38 +0000256 VG_(message)(Vg_UserMsg,
njn25e49d8e72002-09-23 09:36:25 +0000257 "that errors may occur in your program without prior warning from");
sewardj72f98ff2002-06-13 17:23:38 +0000258 VG_(message)(Vg_UserMsg,
259 "Valgrind, because errors are no longer being displayed.");
sewardjde4a1d02002-03-22 01:27:54 +0000260 VG_(message)(Vg_UserMsg, "");
261 stopping_message = True;
262 }
263 return;
264 }
265
266 /* After M_VG_COLLECT_ERRORS_SLOWLY_AFTER different errors have
267 been found, be much more conservative about collecting new
268 ones. */
269 if (vg_n_errs_shown >= M_VG_COLLECT_ERRORS_SLOWLY_AFTER) {
njn25e49d8e72002-09-23 09:36:25 +0000270 exe_res = Vg_LowRes;
sewardjde4a1d02002-03-22 01:27:54 +0000271 if (!slowdown_message) {
272 VG_(message)(Vg_UserMsg, "");
273 VG_(message)(Vg_UserMsg,
274 "More than %d errors detected. Subsequent errors",
275 M_VG_COLLECT_ERRORS_SLOWLY_AFTER);
276 VG_(message)(Vg_UserMsg,
277 "will still be recorded, but in less detail than before.");
278 slowdown_message = True;
279 }
280 }
281
njn25e49d8e72002-09-23 09:36:25 +0000282 /* Build ourselves the error */
283 construct_error ( &err, tst, ekind, a, s, extra );
sewardjde4a1d02002-03-22 01:27:54 +0000284
285 /* First, see if we've got an error record matching this one. */
njn25e49d8e72002-09-23 09:36:25 +0000286 p = vg_errors;
sewardjde4a1d02002-03-22 01:27:54 +0000287 p_prev = NULL;
288 while (p != NULL) {
njn25e49d8e72002-09-23 09:36:25 +0000289 if (eq_CoreError(exe_res, p, &err)) {
sewardjde4a1d02002-03-22 01:27:54 +0000290 /* Found it. */
291 p->count++;
292 if (p->supp != NULL) {
293 /* Deal correctly with suppressed errors. */
294 p->supp->count++;
295 vg_n_errs_suppressed++;
296 } else {
297 vg_n_errs_found++;
298 }
299
300 /* Move p to the front of the list so that future searches
301 for it are faster. */
302 if (p_prev != NULL) {
303 vg_assert(p_prev->next == p);
304 p_prev->next = p->next;
njn25e49d8e72002-09-23 09:36:25 +0000305 p->next = vg_errors;
306 vg_errors = p;
sewardjde4a1d02002-03-22 01:27:54 +0000307 }
308 return;
309 }
310 p_prev = p;
311 p = p->next;
312 }
313
314 /* Didn't see it. Copy and add. */
315
njn25e49d8e72002-09-23 09:36:25 +0000316 /* OK, we're really going to collect it. First make a copy,
317 because the error context is on the stack and will disappear shortly.
318 We can duplicate the main part ourselves, but use
319 SK_(dup_extra_and_update) to duplicate the 'extra' part (unless it's
320 NULL).
321
322 SK_(dup_extra_and_update) can also update the SkinError. This is
323 for when there are more details to fill in which take time to work out
324 but don't affect our earlier decision to include the error -- by
325 postponing those details until now, we avoid the extra work in the
326 case where we ignore the error.
327 */
328 p = VG_(arena_malloc)(VG_AR_ERRORS, sizeof(CoreError));
329 *p = err;
330 if (NULL != err.skin_err.extra)
331 SK_(dup_extra_and_update)(&p->skin_err);
sewardjde4a1d02002-03-22 01:27:54 +0000332
njn25e49d8e72002-09-23 09:36:25 +0000333 p->next = vg_errors;
334 p->supp = is_suppressible_error(&err);
335 vg_errors = p;
sewardjde4a1d02002-03-22 01:27:54 +0000336 if (p->supp == NULL) {
337 vg_n_errs_found++;
338 if (!is_first_shown_context)
339 VG_(message)(Vg_UserMsg, "");
njn25e49d8e72002-09-23 09:36:25 +0000340 pp_CoreError(p, False);
sewardjde4a1d02002-03-22 01:27:54 +0000341 is_first_shown_context = False;
342 vg_n_errs_shown++;
343 /* Perhaps we want a GDB attach at this point? */
344 if (vg_is_GDB_attach_requested()) {
sewardj35805422002-04-21 13:05:34 +0000345 VG_(swizzle_esp_then_start_GDB)(
njn25e49d8e72002-09-23 09:36:25 +0000346 err.m_eip, err.m_esp, err.m_ebp);
sewardjde4a1d02002-03-22 01:27:54 +0000347 }
348 } else {
349 vg_n_errs_suppressed++;
350 p->supp->count++;
351 }
352}
353
354
sewardjde4a1d02002-03-22 01:27:54 +0000355/*------------------------------------------------------------*/
356/*--- Exported fns ---*/
357/*------------------------------------------------------------*/
358
njn25e49d8e72002-09-23 09:36:25 +0000359/* These are called not from generated code but from the scheduler */
sewardj8c824512002-04-14 04:16:48 +0000360
njn25e49d8e72002-09-23 09:36:25 +0000361void VG_(record_pthread_error) ( ThreadId tid, Char* msg )
sewardjde4a1d02002-03-22 01:27:54 +0000362{
njn25e49d8e72002-09-23 09:36:25 +0000363 if (! VG_(needs).core_errors) return;
364 VG_(maybe_record_error)( &VG_(threads)[tid], PThreadErr, /*addr*/0, msg,
365 /*extra*/NULL );
sewardjde4a1d02002-03-22 01:27:54 +0000366}
367
sewardj8c824512002-04-14 04:16:48 +0000368/*------------------------------*/
369
sewardjde4a1d02002-03-22 01:27:54 +0000370void VG_(show_all_errors) ( void )
371{
njn25e49d8e72002-09-23 09:36:25 +0000372 Int i, n_min;
373 Int n_err_contexts, n_supp_contexts;
374 CoreError *p, *p_min;
375 CoreSupp *su;
376 Bool any_supp;
sewardjde4a1d02002-03-22 01:27:54 +0000377
378 if (VG_(clo_verbosity) == 0)
379 return;
380
381 n_err_contexts = 0;
njn25e49d8e72002-09-23 09:36:25 +0000382 for (p = vg_errors; p != NULL; p = p->next) {
sewardjde4a1d02002-03-22 01:27:54 +0000383 if (p->supp == NULL)
384 n_err_contexts++;
385 }
386
387 n_supp_contexts = 0;
388 for (su = vg_suppressions; su != NULL; su = su->next) {
389 if (su->count > 0)
390 n_supp_contexts++;
391 }
392
393 VG_(message)(Vg_UserMsg,
394 "ERROR SUMMARY: "
395 "%d errors from %d contexts (suppressed: %d from %d)",
396 vg_n_errs_found, n_err_contexts,
397 vg_n_errs_suppressed, n_supp_contexts );
398
399 if (VG_(clo_verbosity) <= 1)
400 return;
401
402 /* Print the contexts in order of increasing error count. */
403 for (i = 0; i < n_err_contexts; i++) {
404 n_min = (1 << 30) - 1;
405 p_min = NULL;
njn25e49d8e72002-09-23 09:36:25 +0000406 for (p = vg_errors; p != NULL; p = p->next) {
sewardjde4a1d02002-03-22 01:27:54 +0000407 if (p->supp != NULL) continue;
408 if (p->count < n_min) {
409 n_min = p->count;
410 p_min = p;
411 }
412 }
njn25e49d8e72002-09-23 09:36:25 +0000413 if (p_min == NULL) VG_(panic)("show_all_errors()");
sewardjde4a1d02002-03-22 01:27:54 +0000414
415 VG_(message)(Vg_UserMsg, "");
416 VG_(message)(Vg_UserMsg, "%d errors in context %d of %d:",
417 p_min->count,
418 i+1, n_err_contexts);
njn25e49d8e72002-09-23 09:36:25 +0000419 pp_CoreError( p_min, False );
sewardjde4a1d02002-03-22 01:27:54 +0000420
421 if ((i+1 == VG_(clo_dump_error))) {
sewardj1e8cdc92002-04-18 11:37:52 +0000422 VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to below NULLs */,
423 p_min->where->eips[0], NULL, NULL, NULL );
sewardjde4a1d02002-03-22 01:27:54 +0000424 }
425
426 p_min->count = 1 << 30;
427 }
428
429 if (n_supp_contexts > 0)
430 VG_(message)(Vg_DebugMsg, "");
431 any_supp = False;
432 for (su = vg_suppressions; su != NULL; su = su->next) {
433 if (su->count > 0) {
434 any_supp = True;
njn25e49d8e72002-09-23 09:36:25 +0000435 VG_(message)(Vg_DebugMsg, "supp: %4d %s", su->count, su->sname);
sewardjde4a1d02002-03-22 01:27:54 +0000436 }
437 }
438
439 if (n_err_contexts > 0) {
440 if (any_supp)
441 VG_(message)(Vg_UserMsg, "");
442 VG_(message)(Vg_UserMsg,
443 "IN SUMMARY: "
444 "%d errors from %d contexts (suppressed: %d from %d)",
445 vg_n_errs_found, n_err_contexts,
446 vg_n_errs_suppressed,
447 n_supp_contexts );
448 VG_(message)(Vg_UserMsg, "");
449 }
450}
451
452/*------------------------------------------------------------*/
453/*--- Standard suppressions ---*/
454/*------------------------------------------------------------*/
455
456/* Get a non-blank, non-comment line of at most nBuf chars from fd.
457 Skips leading spaces on the line. Return True if EOF was hit instead.
458*/
459
460#define VG_ISSPACE(ch) (((ch)==' ') || ((ch)=='\n') || ((ch)=='\t'))
461
njn4ba5a792002-09-30 10:23:54 +0000462Bool VG_(get_line) ( Int fd, Char* buf, Int nBuf )
sewardjde4a1d02002-03-22 01:27:54 +0000463{
464 Char ch;
465 Int n, i;
466 while (True) {
467 /* First, read until a non-blank char appears. */
468 while (True) {
469 n = VG_(read)(fd, &ch, 1);
470 if (n == 1 && !VG_ISSPACE(ch)) break;
471 if (n == 0) return True;
472 }
473
474 /* Now, read the line into buf. */
475 i = 0;
476 buf[i++] = ch; buf[i] = 0;
477 while (True) {
478 n = VG_(read)(fd, &ch, 1);
479 if (n == 0) return False; /* the next call will return True */
480 if (ch == '\n') break;
481 if (i > 0 && i == nBuf-1) i--;
482 buf[i++] = ch; buf[i] = 0;
483 }
484 while (i > 1 && VG_ISSPACE(buf[i-1])) {
485 i--; buf[i] = 0;
486 };
487
488 /* VG_(printf)("The line is `%s'\n", buf); */
489 /* Ok, we have a line. If a non-comment line, return.
490 If a comment line, start all over again. */
491 if (buf[0] != '#') return False;
492 }
493}
494
495
496/* *p_caller contains the raw name of a caller, supposedly either
497 fun:some_function_name or
498 obj:some_object_name.
499 Set *p_ty accordingly and advance *p_caller over the descriptor
500 (fun: or obj:) part.
501 Returns False if failed.
502*/
njn25e49d8e72002-09-23 09:36:25 +0000503static Bool setLocationTy ( Char** p_caller, SuppLocTy* p_ty )
sewardjde4a1d02002-03-22 01:27:54 +0000504{
505 if (VG_(strncmp)(*p_caller, "fun:", 4) == 0) {
506 (*p_caller) += 4;
507 *p_ty = FunName;
508 return True;
509 }
510 if (VG_(strncmp)(*p_caller, "obj:", 4) == 0) {
511 (*p_caller) += 4;
512 *p_ty = ObjName;
513 return True;
514 }
515 VG_(printf)("location should start with fun: or obj:\n");
516 return False;
517}
518
519
520/* Read suppressions from the file specified in vg_clo_suppressions
521 and place them in the suppressions list. If there's any difficulty
522 doing this, just give up -- there's no point in trying to recover.
523*/
524#define STREQ(s1,s2) (s1 != NULL && s2 != NULL \
525 && VG_(strcmp)((s1),(s2))==0)
526
sewardjde4a1d02002-03-22 01:27:54 +0000527static void load_one_suppressions_file ( Char* filename )
528{
529# define N_BUF 200
njn25e49d8e72002-09-23 09:36:25 +0000530 Int fd, i;
sewardjde4a1d02002-03-22 01:27:54 +0000531 Bool eof;
njn25e49d8e72002-09-23 09:36:25 +0000532 Bool is_unrecognised_suppressions = False;
sewardjde4a1d02002-03-22 01:27:54 +0000533 Char buf[N_BUF+1];
njn25e49d8e72002-09-23 09:36:25 +0000534 fd = VG_(open)( filename, VKI_O_RDONLY, 0 );
sewardjde4a1d02002-03-22 01:27:54 +0000535 if (fd == -1) {
njn25e49d8e72002-09-23 09:36:25 +0000536 VG_(message)(Vg_UserMsg, "FATAL: can't open suppressions file `%s'",
sewardjde4a1d02002-03-22 01:27:54 +0000537 filename );
538 VG_(exit)(1);
539 }
540
541 while (True) {
njn25e49d8e72002-09-23 09:36:25 +0000542 /* Assign and initialise the two suppression halves (core and skin) */
543 CoreSupp* supp;
544 supp = VG_(arena_malloc)(VG_AR_CORE, sizeof(CoreSupp));
sewardjde4a1d02002-03-22 01:27:54 +0000545 supp->count = 0;
njn25e49d8e72002-09-23 09:36:25 +0000546 for (i = 0; i < VG_N_SUPP_CALLERS; i++) supp->caller[i] = NULL;
547 supp->skin_supp.string = supp->skin_supp.extra = NULL;
sewardjde4a1d02002-03-22 01:27:54 +0000548
njn4ba5a792002-09-30 10:23:54 +0000549 eof = VG_(get_line) ( fd, buf, N_BUF );
sewardjde4a1d02002-03-22 01:27:54 +0000550 if (eof) break;
551
552 if (!STREQ(buf, "{")) goto syntax_error;
553
njn4ba5a792002-09-30 10:23:54 +0000554 eof = VG_(get_line) ( fd, buf, N_BUF );
sewardjde4a1d02002-03-22 01:27:54 +0000555 if (eof || STREQ(buf, "}")) goto syntax_error;
njn25e49d8e72002-09-23 09:36:25 +0000556 supp->sname = VG_(arena_strdup)(VG_AR_CORE, buf);
sewardjde4a1d02002-03-22 01:27:54 +0000557
njn4ba5a792002-09-30 10:23:54 +0000558 eof = VG_(get_line) ( fd, buf, N_BUF );
njn25e49d8e72002-09-23 09:36:25 +0000559
sewardjde4a1d02002-03-22 01:27:54 +0000560 if (eof) goto syntax_error;
sewardjde4a1d02002-03-22 01:27:54 +0000561
njn25e49d8e72002-09-23 09:36:25 +0000562 /* Is it a core suppression? */
563 else if (VG_(needs).core_errors && STREQ(buf, "PThread"))
564 supp->skin_supp.skind = PThreadSupp;
565
566 /* Is it a skin suppression? */
567 else if (VG_(needs).skin_errors &&
568 SK_(recognised_suppression)(buf, &(supp->skin_supp.skind))) {
569 /* do nothing, function fills in supp->skin_supp.skind */
570 }
571 //else goto syntax_error;
572 else {
573 /* SSS: if we don't recognise the suppression name, ignore entire
574 * entry. Not sure if this is a good long-term approach -- makes
575 * it impossible to spot incorrect suppression names? (apart
576 * from the warning given) */
577 if (! is_unrecognised_suppressions) {
578 is_unrecognised_suppressions = True;
579 VG_(start_msg)(Vg_DebugMsg);
580 VG_(add_to_msg)("Ignoring unrecognised suppressions: ");
581 VG_(add_to_msg)("'%s'", buf);
582 } else {
583 VG_(add_to_msg)(", '%s'", buf);
584 }
585 while (True) {
njn4ba5a792002-09-30 10:23:54 +0000586 eof = VG_(get_line) ( fd, buf, N_BUF );
njn25e49d8e72002-09-23 09:36:25 +0000587 if (eof) goto syntax_error;
588 if (STREQ(buf, "}"))
589 break;
590 }
591 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000592 }
593
njn25e49d8e72002-09-23 09:36:25 +0000594 if (VG_(needs).skin_errors &&
595 !SK_(read_extra_suppression_info)(fd, buf, N_BUF, &supp->skin_supp))
sewardjde4a1d02002-03-22 01:27:54 +0000596 goto syntax_error;
597
njn25e49d8e72002-09-23 09:36:25 +0000598 /* "i > 0" ensures at least one caller read. */
599 for (i = 0; i < VG_N_SUPP_CALLERS; i++) {
njn4ba5a792002-09-30 10:23:54 +0000600 eof = VG_(get_line) ( fd, buf, N_BUF );
sewardjde4a1d02002-03-22 01:27:54 +0000601 if (eof) goto syntax_error;
njn25e49d8e72002-09-23 09:36:25 +0000602 if (i > 0 && STREQ(buf, "}"))
603 break;
604 supp->caller[i] = VG_(arena_strdup)(VG_AR_CORE, buf);
605 if (!setLocationTy(&(supp->caller[i]), &(supp->caller_ty[i])))
606 goto syntax_error;
sewardjde4a1d02002-03-22 01:27:54 +0000607 }
608
609 supp->next = vg_suppressions;
610 vg_suppressions = supp;
611 }
njn25e49d8e72002-09-23 09:36:25 +0000612 if (is_unrecognised_suppressions) {
613 /* Print out warning about any ignored suppressions */
614 //VG_(end_msg)();
615 }
sewardjde4a1d02002-03-22 01:27:54 +0000616 VG_(close)(fd);
617 return;
618
619 syntax_error:
620 if (eof) {
621 VG_(message)(Vg_UserMsg,
622 "FATAL: in suppressions file `%s': unexpected EOF",
623 filename );
624 } else {
625 VG_(message)(Vg_UserMsg,
626 "FATAL: in suppressions file `%s': syntax error on: %s",
627 filename, buf );
628 }
629 VG_(close)(fd);
630 VG_(message)(Vg_UserMsg, "exiting now.");
631 VG_(exit)(1);
632
633# undef N_BUF
634}
635
636
637void VG_(load_suppressions) ( void )
638{
639 Int i;
640 vg_suppressions = NULL;
641 for (i = 0; i < VG_(clo_n_suppressions); i++) {
642 if (VG_(clo_verbosity) > 1) {
643 VG_(message)(Vg_UserMsg, "Reading suppressions file: %s",
644 VG_(clo_suppressions)[i] );
645 }
646 load_one_suppressions_file( VG_(clo_suppressions)[i] );
647 }
648}
649
njn25e49d8e72002-09-23 09:36:25 +0000650/* Return the name of an erring fn in a way which is useful
651 for comparing against the contents of a suppressions file.
652 Doesn't demangle the fn name, because we want to refer to
653 mangled names in the suppressions file.
654*/
655static
656void get_objname_fnname ( Addr a,
657 Char* obj_buf, Int n_obj_buf,
658 Char* fun_buf, Int n_fun_buf )
659{
660 (void)VG_(get_objname) ( a, obj_buf, n_obj_buf );
661 (void)VG_(get_fnname_nodemangle)( a, fun_buf, n_fun_buf );
662}
663
664static __inline__
665Bool supp_matches_error(CoreSupp* su, CoreError* err)
666{
667 switch (su->skin_supp.skind) {
668 case PThreadSupp:
669 return (err->skin_err.ekind == PThreadErr);
670 default:
671 if (VG_(needs).skin_errors) {
672 return (SK_(error_matches_suppression)(&err->skin_err,
673 &su->skin_supp));
674 } else {
675 VG_(printf)(
676 "\nUnhandled suppression type: %u. VG_(needs).skin_errors\n"
677 "probably needs to be set.\n",
678 err->skin_err.ekind);
679 VG_(skin_error)("unhandled suppression type");
680 }
681 }
682}
683
684static __inline__
685Bool supp_matches_callers(CoreSupp* su, Char caller_obj[][M_VG_ERRTXT],
686 Char caller_fun[][M_VG_ERRTXT])
687{
688 Int i;
689
690 for (i = 0; su->caller[i] != NULL; i++) {
691 switch (su->caller_ty[i]) {
njn4ba5a792002-09-30 10:23:54 +0000692 case ObjName: if (VG_(string_match)(su->caller[i],
693 caller_obj[i])) break;
njn25e49d8e72002-09-23 09:36:25 +0000694 return False;
njn4ba5a792002-09-30 10:23:54 +0000695 case FunName: if (VG_(string_match)(su->caller[i],
696 caller_fun[i])) break;
njn25e49d8e72002-09-23 09:36:25 +0000697 return False;
698 default: VG_(panic)("is_suppressible_error");
699 }
700 }
701
702 /* If we reach here, it's a match */
703 return True;
704}
sewardjde4a1d02002-03-22 01:27:54 +0000705
706/* Does an error context match a suppression? ie is this a
njn25e49d8e72002-09-23 09:36:25 +0000707 suppressible error? If so, return a pointer to the CoreSupp
sewardjde4a1d02002-03-22 01:27:54 +0000708 record, otherwise NULL.
njn25e49d8e72002-09-23 09:36:25 +0000709 Tries to minimise the number of symbol searches since they are expensive.
sewardjde4a1d02002-03-22 01:27:54 +0000710*/
njn25e49d8e72002-09-23 09:36:25 +0000711static CoreSupp* is_suppressible_error ( CoreError* err )
sewardjde4a1d02002-03-22 01:27:54 +0000712{
713# define STREQ(s1,s2) (s1 != NULL && s2 != NULL \
714 && VG_(strcmp)((s1),(s2))==0)
njn25e49d8e72002-09-23 09:36:25 +0000715 Int i;
sewardjde4a1d02002-03-22 01:27:54 +0000716
njn25e49d8e72002-09-23 09:36:25 +0000717 Char caller_obj[VG_N_SUPP_CALLERS][M_VG_ERRTXT];
718 Char caller_fun[VG_N_SUPP_CALLERS][M_VG_ERRTXT];
sewardjde4a1d02002-03-22 01:27:54 +0000719
njn25e49d8e72002-09-23 09:36:25 +0000720 CoreSupp* su;
sewardjde4a1d02002-03-22 01:27:54 +0000721
njn25e49d8e72002-09-23 09:36:25 +0000722 /* get_objname_fnname() writes the function name and object name if
723 it finds them in the debug info. so the strings in the suppression
724 file should match these.
sewardjde4a1d02002-03-22 01:27:54 +0000725 */
726
727 /* Initialise these strs so they are always safe to compare, even
njn25e49d8e72002-09-23 09:36:25 +0000728 if get_objname_fnname doesn't write anything to them. */
729 for (i = 0; i < VG_N_SUPP_CALLERS; i++)
730 caller_obj[i][0] = caller_fun[i][0] = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000731
njn25e49d8e72002-09-23 09:36:25 +0000732 for (i = 0; i < VG_N_SUPP_CALLERS && i < VG_(clo_backtrace_size); i++) {
733 get_objname_fnname ( err->where->eips[i],
734 caller_obj[i], M_VG_ERRTXT,
735 caller_fun[i], M_VG_ERRTXT );
sewardjde4a1d02002-03-22 01:27:54 +0000736 }
737
738 /* See if the error context matches any suppression. */
739 for (su = vg_suppressions; su != NULL; su = su->next) {
njn25e49d8e72002-09-23 09:36:25 +0000740 if (supp_matches_error(su, err) &&
741 supp_matches_callers(su, caller_obj, caller_fun)) {
742 return su;
sewardjde4a1d02002-03-22 01:27:54 +0000743 }
sewardjde4a1d02002-03-22 01:27:54 +0000744 }
njn25e49d8e72002-09-23 09:36:25 +0000745 return NULL; /* no matches */
sewardjde4a1d02002-03-22 01:27:54 +0000746
747# undef STREQ
748}
749
750/*--------------------------------------------------------------------*/
751/*--- end vg_errcontext.c ---*/
752/*--------------------------------------------------------------------*/