blob: b01ca574c39ee0e3c3d17c29796e612efa5ad012 [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. */
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);
njne427a662002-10-02 11:08:25 +000084 VG_(skin_panic)("unhandled error type");
njn25e49d8e72002-09-23 09:36:25 +000085 }
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);
njne427a662002-10-02 11:08:25 +0000116 VG_(skin_panic)("unhandled error type");
njn25e49d8e72002-09-23 09:36:25 +0000117 }
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 }
njne427a662002-10-02 11:08:25 +0000413 if (p_min == NULL) VG_(skin_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
njn11cc9252002-10-07 14:42:59 +0000520/* Look for "skin" in a string like "skin1,skin2,skin3" */
521static __inline__
522Bool skin_name_present(Char *name, Char *names)
523{
524 Bool found;
525 Char *s = NULL; /* Shut gcc up */
526 Int len = VG_(strlen)(name);
527
528 found = (NULL != (s = VG_(strstr)(names, name)) &&
529 (s == names || *(s-1) == ',') &&
530 (*(s+len) == ',' || *(s+len) == '\0')
531 );
532
533 return found;
534}
535
536#define STREQ(s1,s2) (s1 != NULL && s2 != NULL \
537 && VG_(strcmp)((s1),(s2))==0)
538
sewardjde4a1d02002-03-22 01:27:54 +0000539/* Read suppressions from the file specified in vg_clo_suppressions
540 and place them in the suppressions list. If there's any difficulty
541 doing this, just give up -- there's no point in trying to recover.
542*/
sewardjde4a1d02002-03-22 01:27:54 +0000543static void load_one_suppressions_file ( Char* filename )
544{
545# define N_BUF 200
njnc40c3a82002-10-02 11:02:27 +0000546 Int fd, i;
547 Bool eof;
548 Char buf[N_BUF+1];
njn11cc9252002-10-07 14:42:59 +0000549 Char* skin_names;
njnc40c3a82002-10-02 11:02:27 +0000550 Char* supp_name;
551
njn25e49d8e72002-09-23 09:36:25 +0000552 fd = VG_(open)( filename, VKI_O_RDONLY, 0 );
sewardjde4a1d02002-03-22 01:27:54 +0000553 if (fd == -1) {
njn25e49d8e72002-09-23 09:36:25 +0000554 VG_(message)(Vg_UserMsg, "FATAL: can't open suppressions file `%s'",
sewardjde4a1d02002-03-22 01:27:54 +0000555 filename );
556 VG_(exit)(1);
557 }
558
559 while (True) {
njn25e49d8e72002-09-23 09:36:25 +0000560 /* Assign and initialise the two suppression halves (core and skin) */
561 CoreSupp* supp;
njnc40c3a82002-10-02 11:02:27 +0000562 supp = VG_(arena_malloc)(VG_AR_CORE, sizeof(CoreSupp));
sewardjde4a1d02002-03-22 01:27:54 +0000563 supp->count = 0;
njn25e49d8e72002-09-23 09:36:25 +0000564 for (i = 0; i < VG_N_SUPP_CALLERS; i++) supp->caller[i] = NULL;
565 supp->skin_supp.string = supp->skin_supp.extra = NULL;
sewardjde4a1d02002-03-22 01:27:54 +0000566
njn4ba5a792002-09-30 10:23:54 +0000567 eof = VG_(get_line) ( fd, buf, N_BUF );
sewardjde4a1d02002-03-22 01:27:54 +0000568 if (eof) break;
569
570 if (!STREQ(buf, "{")) goto syntax_error;
571
njn4ba5a792002-09-30 10:23:54 +0000572 eof = VG_(get_line) ( fd, buf, N_BUF );
sewardjde4a1d02002-03-22 01:27:54 +0000573 if (eof || STREQ(buf, "}")) goto syntax_error;
njn25e49d8e72002-09-23 09:36:25 +0000574 supp->sname = VG_(arena_strdup)(VG_AR_CORE, buf);
sewardjde4a1d02002-03-22 01:27:54 +0000575
njn4ba5a792002-09-30 10:23:54 +0000576 eof = VG_(get_line) ( fd, buf, N_BUF );
njn25e49d8e72002-09-23 09:36:25 +0000577
sewardjde4a1d02002-03-22 01:27:54 +0000578 if (eof) goto syntax_error;
sewardjde4a1d02002-03-22 01:27:54 +0000579
njn11cc9252002-10-07 14:42:59 +0000580 /* Check it has the "skin1,skin2,...:supp" form (look for ':') */
njnc40c3a82002-10-02 11:02:27 +0000581 i = 0;
582 while (True) {
583 if (buf[i] == ':') break;
584 if (buf[i] == '\0') goto syntax_error;
585 i++;
njn25e49d8e72002-09-23 09:36:25 +0000586 }
njnc40c3a82002-10-02 11:02:27 +0000587 buf[i] = '\0'; /* Replace ':', splitting into two strings */
588
njn11cc9252002-10-07 14:42:59 +0000589 skin_names = & buf[0];
590 supp_name = & buf[i+1];
njnc40c3a82002-10-02 11:02:27 +0000591
njn11cc9252002-10-07 14:42:59 +0000592 /* Is it a core suppression? */
593 if (VG_(needs).core_errors && skin_name_present("core", skin_names))
njnc40c3a82002-10-02 11:02:27 +0000594 {
njn11cc9252002-10-07 14:42:59 +0000595 if (STREQ(supp_name, "PThread"))
njnc40c3a82002-10-02 11:02:27 +0000596 supp->skin_supp.skind = PThreadSupp;
597 else
598 goto syntax_error;
599 }
600
njn11cc9252002-10-07 14:42:59 +0000601 /* Is it a skin suppression? */
602 else if (VG_(needs).skin_errors &&
603 skin_name_present(VG_(details).name, skin_names))
njnc40c3a82002-10-02 11:02:27 +0000604 {
605 if (SK_(recognised_suppression)(supp_name, & supp->skin_supp.skind))
606 {
607 /* Do nothing, function fills in supp->skin_supp.skind */
608 } else
609 goto syntax_error;
610 }
611
njn25e49d8e72002-09-23 09:36:25 +0000612 else {
njnc40c3a82002-10-02 11:02:27 +0000613 /* Ignore rest of suppression */
njn25e49d8e72002-09-23 09:36:25 +0000614 while (True) {
njn4ba5a792002-09-30 10:23:54 +0000615 eof = VG_(get_line) ( fd, buf, N_BUF );
njn25e49d8e72002-09-23 09:36:25 +0000616 if (eof) goto syntax_error;
617 if (STREQ(buf, "}"))
618 break;
619 }
620 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000621 }
622
njn25e49d8e72002-09-23 09:36:25 +0000623 if (VG_(needs).skin_errors &&
624 !SK_(read_extra_suppression_info)(fd, buf, N_BUF, &supp->skin_supp))
sewardjde4a1d02002-03-22 01:27:54 +0000625 goto syntax_error;
626
njn25e49d8e72002-09-23 09:36:25 +0000627 /* "i > 0" ensures at least one caller read. */
628 for (i = 0; i < VG_N_SUPP_CALLERS; i++) {
njn4ba5a792002-09-30 10:23:54 +0000629 eof = VG_(get_line) ( fd, buf, N_BUF );
sewardjde4a1d02002-03-22 01:27:54 +0000630 if (eof) goto syntax_error;
njn25e49d8e72002-09-23 09:36:25 +0000631 if (i > 0 && STREQ(buf, "}"))
632 break;
633 supp->caller[i] = VG_(arena_strdup)(VG_AR_CORE, buf);
634 if (!setLocationTy(&(supp->caller[i]), &(supp->caller_ty[i])))
635 goto syntax_error;
sewardjde4a1d02002-03-22 01:27:54 +0000636 }
637
638 supp->next = vg_suppressions;
639 vg_suppressions = supp;
640 }
sewardjde4a1d02002-03-22 01:27:54 +0000641 VG_(close)(fd);
642 return;
643
644 syntax_error:
645 if (eof) {
646 VG_(message)(Vg_UserMsg,
647 "FATAL: in suppressions file `%s': unexpected EOF",
648 filename );
649 } else {
650 VG_(message)(Vg_UserMsg,
njn11cc9252002-10-07 14:42:59 +0000651 "FATAL: in suppressions file: `%s': syntax error on: %s",
sewardjde4a1d02002-03-22 01:27:54 +0000652 filename, buf );
653 }
654 VG_(close)(fd);
655 VG_(message)(Vg_UserMsg, "exiting now.");
656 VG_(exit)(1);
657
658# undef N_BUF
659}
660
661
662void VG_(load_suppressions) ( void )
663{
664 Int i;
665 vg_suppressions = NULL;
666 for (i = 0; i < VG_(clo_n_suppressions); i++) {
667 if (VG_(clo_verbosity) > 1) {
668 VG_(message)(Vg_UserMsg, "Reading suppressions file: %s",
669 VG_(clo_suppressions)[i] );
670 }
671 load_one_suppressions_file( VG_(clo_suppressions)[i] );
672 }
673}
674
njn25e49d8e72002-09-23 09:36:25 +0000675/* Return the name of an erring fn in a way which is useful
676 for comparing against the contents of a suppressions file.
677 Doesn't demangle the fn name, because we want to refer to
678 mangled names in the suppressions file.
679*/
680static
681void get_objname_fnname ( Addr a,
682 Char* obj_buf, Int n_obj_buf,
683 Char* fun_buf, Int n_fun_buf )
684{
685 (void)VG_(get_objname) ( a, obj_buf, n_obj_buf );
686 (void)VG_(get_fnname_nodemangle)( a, fun_buf, n_fun_buf );
687}
688
689static __inline__
690Bool supp_matches_error(CoreSupp* su, CoreError* err)
691{
692 switch (su->skin_supp.skind) {
693 case PThreadSupp:
694 return (err->skin_err.ekind == PThreadErr);
695 default:
696 if (VG_(needs).skin_errors) {
697 return (SK_(error_matches_suppression)(&err->skin_err,
698 &su->skin_supp));
699 } else {
700 VG_(printf)(
701 "\nUnhandled suppression type: %u. VG_(needs).skin_errors\n"
702 "probably needs to be set.\n",
703 err->skin_err.ekind);
njne427a662002-10-02 11:08:25 +0000704 VG_(skin_panic)("unhandled suppression type");
njn25e49d8e72002-09-23 09:36:25 +0000705 }
706 }
707}
708
709static __inline__
710Bool supp_matches_callers(CoreSupp* su, Char caller_obj[][M_VG_ERRTXT],
711 Char caller_fun[][M_VG_ERRTXT])
712{
713 Int i;
714
715 for (i = 0; su->caller[i] != NULL; i++) {
716 switch (su->caller_ty[i]) {
njn4ba5a792002-09-30 10:23:54 +0000717 case ObjName: if (VG_(string_match)(su->caller[i],
718 caller_obj[i])) break;
njn25e49d8e72002-09-23 09:36:25 +0000719 return False;
njn4ba5a792002-09-30 10:23:54 +0000720 case FunName: if (VG_(string_match)(su->caller[i],
721 caller_fun[i])) break;
njn25e49d8e72002-09-23 09:36:25 +0000722 return False;
njne427a662002-10-02 11:08:25 +0000723 default: VG_(skin_panic)("is_suppressible_error");
njn25e49d8e72002-09-23 09:36:25 +0000724 }
725 }
726
727 /* If we reach here, it's a match */
728 return True;
729}
sewardjde4a1d02002-03-22 01:27:54 +0000730
731/* Does an error context match a suppression? ie is this a
njn25e49d8e72002-09-23 09:36:25 +0000732 suppressible error? If so, return a pointer to the CoreSupp
sewardjde4a1d02002-03-22 01:27:54 +0000733 record, otherwise NULL.
njn25e49d8e72002-09-23 09:36:25 +0000734 Tries to minimise the number of symbol searches since they are expensive.
sewardjde4a1d02002-03-22 01:27:54 +0000735*/
njn25e49d8e72002-09-23 09:36:25 +0000736static CoreSupp* is_suppressible_error ( CoreError* err )
sewardjde4a1d02002-03-22 01:27:54 +0000737{
njn25e49d8e72002-09-23 09:36:25 +0000738 Int i;
sewardjde4a1d02002-03-22 01:27:54 +0000739
njn25e49d8e72002-09-23 09:36:25 +0000740 Char caller_obj[VG_N_SUPP_CALLERS][M_VG_ERRTXT];
741 Char caller_fun[VG_N_SUPP_CALLERS][M_VG_ERRTXT];
sewardjde4a1d02002-03-22 01:27:54 +0000742
njn25e49d8e72002-09-23 09:36:25 +0000743 CoreSupp* su;
sewardjde4a1d02002-03-22 01:27:54 +0000744
njn25e49d8e72002-09-23 09:36:25 +0000745 /* get_objname_fnname() writes the function name and object name if
746 it finds them in the debug info. so the strings in the suppression
747 file should match these.
sewardjde4a1d02002-03-22 01:27:54 +0000748 */
749
750 /* Initialise these strs so they are always safe to compare, even
njn25e49d8e72002-09-23 09:36:25 +0000751 if get_objname_fnname doesn't write anything to them. */
752 for (i = 0; i < VG_N_SUPP_CALLERS; i++)
753 caller_obj[i][0] = caller_fun[i][0] = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000754
njn25e49d8e72002-09-23 09:36:25 +0000755 for (i = 0; i < VG_N_SUPP_CALLERS && i < VG_(clo_backtrace_size); i++) {
756 get_objname_fnname ( err->where->eips[i],
757 caller_obj[i], M_VG_ERRTXT,
758 caller_fun[i], M_VG_ERRTXT );
sewardjde4a1d02002-03-22 01:27:54 +0000759 }
760
761 /* See if the error context matches any suppression. */
762 for (su = vg_suppressions; su != NULL; su = su->next) {
njn25e49d8e72002-09-23 09:36:25 +0000763 if (supp_matches_error(su, err) &&
764 supp_matches_callers(su, caller_obj, caller_fun)) {
765 return su;
sewardjde4a1d02002-03-22 01:27:54 +0000766 }
sewardjde4a1d02002-03-22 01:27:54 +0000767 }
njn25e49d8e72002-09-23 09:36:25 +0000768 return NULL; /* no matches */
sewardjde4a1d02002-03-22 01:27:54 +0000769}
770
njn11cc9252002-10-07 14:42:59 +0000771#undef STREQ
772
sewardjde4a1d02002-03-22 01:27:54 +0000773/*--------------------------------------------------------------------*/
774/*--- end vg_errcontext.c ---*/
775/*--------------------------------------------------------------------*/