blob: a5fd02d9592aef83619e70c333be911c7a29e560 [file] [log] [blame]
sewardjde4a1d02002-03-22 01:27:54 +00001
2/*--------------------------------------------------------------------*/
sewardj267100d2005-04-24 12:33:12 +00003/*--- Management of error messages. m_errormgr.c ---*/
sewardjde4a1d02002-03-22 01:27:54 +00004/*--------------------------------------------------------------------*/
5
6/*
njnb9c427c2004-12-01 14:14:42 +00007 This file is part of Valgrind, a dynamic binary instrumentation
8 framework.
sewardjde4a1d02002-03-22 01:27:54 +00009
njn53612422005-03-12 16:22:54 +000010 Copyright (C) 2000-2005 Julian Seward
sewardjde4a1d02002-03-22 01:27:54 +000011 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
njnc7561b92005-06-19 01:24:32 +000031#include "pub_core_basics.h"
njn24a6efb2005-06-20 03:36:51 +000032#include "pub_core_threadstate.h" // For VG_N_THREADS
njn75b65aa2005-06-19 19:25:44 +000033#include "pub_core_debugger.h"
njnea27e462005-05-31 02:38:09 +000034#include "pub_core_debuginfo.h"
njnd2b17112005-04-19 04:10:25 +000035#include "pub_core_errormgr.h"
njnd01fef72005-03-25 23:35:48 +000036#include "pub_core_execontext.h"
njn97405b22005-06-02 03:39:33 +000037#include "pub_core_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000038#include "pub_core_libcassert.h"
njneb8896b2005-06-04 20:03:55 +000039#include "pub_core_libcfile.h"
njn36a20fa2005-06-03 03:08:39 +000040#include "pub_core_libcprint.h"
njn24a6efb2005-06-20 03:36:51 +000041#include "pub_core_libcproc.h" // For VG_(getpid)()
njnaf1d7df2005-06-11 01:31:52 +000042#include "pub_core_mallocfree.h"
njn20242342005-05-16 23:31:24 +000043#include "pub_core_options.h"
njnd0d7c1f2005-06-21 00:33:19 +000044#include "pub_core_stacktrace.h"
njn43b9a8a2005-05-10 04:37:01 +000045#include "pub_core_tooliface.h"
njn24a6efb2005-06-20 03:36:51 +000046#include "pub_core_translate.h" // for VG_(translate)()
sewardjde4a1d02002-03-22 01:27:54 +000047
48/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +000049/*--- Globals ---*/
sewardjde4a1d02002-03-22 01:27:54 +000050/*------------------------------------------------------------*/
51
njn14319cc2005-03-13 06:26:22 +000052/* After this many different unsuppressed errors have been observed,
53 be more conservative about collecting new ones. */
sewardj1d1a2262005-10-20 01:57:29 +000054#define M_COLLECT_ERRORS_SLOWLY_AFTER 100
njn14319cc2005-03-13 06:26:22 +000055
56/* After this many different unsuppressed errors have been observed,
57 stop collecting errors at all, and tell the user their program is
58 evidently a steaming pile of camel dung. */
sewardj1d1a2262005-10-20 01:57:29 +000059#define M_COLLECT_NO_ERRORS_AFTER_SHOWN 1000
njn14319cc2005-03-13 06:26:22 +000060
61/* After this many total errors have been observed, stop collecting
62 errors at all. Counterpart to M_COLLECT_NO_ERRORS_AFTER_SHOWN. */
sewardj1d1a2262005-10-20 01:57:29 +000063#define M_COLLECT_NO_ERRORS_AFTER_FOUND 100000
njn14319cc2005-03-13 06:26:22 +000064
sewardjde4a1d02002-03-22 01:27:54 +000065/* The list of error contexts found, both suppressed and unsuppressed.
66 Initially empty, and grows as errors are detected. */
njn695c16e2005-03-27 03:40:28 +000067static Error* errors = NULL;
sewardjde4a1d02002-03-22 01:27:54 +000068
69/* The list of suppression directives, as read from the specified
70 suppressions file. */
njn695c16e2005-03-27 03:40:28 +000071static Supp* suppressions = NULL;
sewardjde4a1d02002-03-22 01:27:54 +000072
73/* Running count of unsuppressed errors detected. */
nethercotef2b11482004-08-02 12:36:01 +000074static UInt n_errs_found = 0;
sewardjde4a1d02002-03-22 01:27:54 +000075
76/* Running count of suppressed errors detected. */
nethercotef2b11482004-08-02 12:36:01 +000077static UInt n_errs_suppressed = 0;
sewardjde4a1d02002-03-22 01:27:54 +000078
79/* forwards ... */
njn810086f2002-11-14 12:42:47 +000080static Supp* is_suppressible_error ( Error* err );
sewardjde4a1d02002-03-22 01:27:54 +000081
sewardjb5f6f512005-03-10 23:59:00 +000082static ThreadId last_tid_printed = 1;
sewardjde4a1d02002-03-22 01:27:54 +000083
84/*------------------------------------------------------------*/
nethercote4a184902004-08-02 12:21:09 +000085/*--- Error type ---*/
86/*------------------------------------------------------------*/
87
nethercote996901a2004-08-03 13:29:09 +000088/* Note: it is imperative this doesn't overlap with (0..) at all, as tools
nethercote4a184902004-08-02 12:21:09 +000089 * effectively extend it by defining their own enums in the (0..) range. */
nethercote4a184902004-08-02 12:21:09 +000090
91/* Errors. Extensible (via the 'extra' field). Tools can use a normal
njn02bc4b82005-05-15 17:28:26 +000092 enum (with element values in the normal range (0..)) for 'ekind'.
nethercote4a184902004-08-02 12:21:09 +000093 Functions for getting/setting the tool-relevant fields are in
njnc7561b92005-06-19 01:24:32 +000094 include/pub_tool_errormgr.h.
nethercote4a184902004-08-02 12:21:09 +000095
96 When errors are found and recorded with VG_(maybe_record_error)(), all
97 the tool must do is pass in the four parameters; core will
98 allocate/initialise the error record.
99*/
100struct _Error {
101 struct _Error* next;
sewardjdbada272005-07-02 21:16:30 +0000102 // Unique tag. This gives the error a unique identity (handle) by
103 // which it can be referred to afterwords. Currently only used for
104 // XML printing.
105 UInt unique;
nethercote4a184902004-08-02 12:21:09 +0000106 // NULL if unsuppressed; or ptr to suppression record.
107 Supp* supp;
108 Int count;
109 ThreadId tid;
110
111 // The tool-specific part
112 ExeContext* where; // Initialised by core
njnd2b17112005-04-19 04:10:25 +0000113 ErrorKind ekind; // Used by ALL. Must be in the range (0..)
nethercote4a184902004-08-02 12:21:09 +0000114 Addr addr; // Used frequently
115 Char* string; // Used frequently
116 void* extra; // For any tool-specific extras
117};
118
119ExeContext* VG_(get_error_where) ( Error* err )
120{
121 return err->where;
122}
123
124ErrorKind VG_(get_error_kind) ( Error* err )
125{
126 return err->ekind;
127}
128
129Addr VG_(get_error_address) ( Error* err )
130{
131 return err->addr;
132}
133
134Char* VG_(get_error_string) ( Error* err )
135{
136 return err->string;
137}
138
139void* VG_(get_error_extra) ( Error* err )
140{
141 return err->extra;
142}
143
nethercotef2b11482004-08-02 12:36:01 +0000144UInt VG_(get_n_errs_found)( void )
145{
146 return n_errs_found;
147}
148
nethercote4a184902004-08-02 12:21:09 +0000149/*------------------------------------------------------------*/
150/*--- Suppression type ---*/
151/*------------------------------------------------------------*/
152
153/* Note: it is imperative this doesn't overlap with (0..) at all, as tools
154 * effectively extend it by defining their own enums in the (0..) range. */
155typedef
156 enum {
157 PThreadSupp = -1, /* Matches PThreadErr */
158 }
159 CoreSuppKind;
160
sewardjb5f6f512005-03-10 23:59:00 +0000161/* Max number of callers for context in a suppression. */
162#define VG_MAX_SUPP_CALLERS 24
163
nethercote4a184902004-08-02 12:21:09 +0000164/* For each caller specified for a suppression, record the nature of
165 the caller name. Not of interest to tools. */
166typedef
167 enum {
sewardjb5f6f512005-03-10 23:59:00 +0000168 NoName, /* Error case */
nethercote4a184902004-08-02 12:21:09 +0000169 ObjName, /* Name is of an shared object file. */
170 FunName /* Name is of a function. */
171 }
172 SuppLocTy;
173
sewardjb5f6f512005-03-10 23:59:00 +0000174typedef
175 struct {
176 SuppLocTy ty;
177 Char* name;
178 }
179 SuppLoc;
180
nethercote4a184902004-08-02 12:21:09 +0000181/* Suppressions. Tools can get/set tool-relevant parts with functions
njnc7561b92005-06-19 01:24:32 +0000182 declared in include/pub_tool_errormgr.h. Extensible via the 'extra' field.
nethercote4a184902004-08-02 12:21:09 +0000183 Tools can use a normal enum (with element values in the normal range
njn02bc4b82005-05-15 17:28:26 +0000184 (0..)) for 'skind'. */
nethercote4a184902004-08-02 12:21:09 +0000185struct _Supp {
186 struct _Supp* next;
187 Int count; // The number of times this error has been suppressed.
188 Char* sname; // The name by which the suppression is referred to.
sewardjb5f6f512005-03-10 23:59:00 +0000189
190 // Length of 'callers'
191 Int n_callers;
192 // Array of callers, for matching stack traces. First one (name of fn
193 // where err occurs) is mandatory; rest are optional.
194 SuppLoc* callers;
nethercote4a184902004-08-02 12:21:09 +0000195
196 /* The tool-specific part */
197 SuppKind skind; // What kind of suppression. Must use the range (0..).
198 Char* string; // String -- use is optional. NULL by default.
199 void* extra; // Anything else -- use is optional. NULL by default.
200};
201
202SuppKind VG_(get_supp_kind) ( Supp* su )
203{
204 return su->skind;
205}
206
207Char* VG_(get_supp_string) ( Supp* su )
208{
209 return su->string;
210}
211
212void* VG_(get_supp_extra) ( Supp* su )
213{
214 return su->extra;
215}
216
217
218void VG_(set_supp_kind) ( Supp* su, SuppKind skind )
219{
220 su->skind = skind;
221}
222
223void VG_(set_supp_string) ( Supp* su, Char* string )
224{
225 su->string = string;
226}
227
228void VG_(set_supp_extra) ( Supp* su, void* extra )
229{
230 su->extra = extra;
231}
232
233
234/*------------------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +0000235/*--- Helper fns ---*/
236/*------------------------------------------------------------*/
237
njn0087c502005-07-01 04:15:36 +0000238// Only show core errors if the tool wants to, we're not running with -q,
239// and were not outputting XML.
240Bool VG_(showing_core_errors)(void)
241{
242 return VG_(needs).core_errors && VG_(clo_verbosity) >= 1 && !VG_(clo_xml);
243}
244
sewardjde4a1d02002-03-22 01:27:54 +0000245/* Compare error contexts, to detect duplicates. Note that if they
246 are otherwise the same, the faulting addrs and associated rwoffsets
247 are allowed to be different. */
njn810086f2002-11-14 12:42:47 +0000248static Bool eq_Error ( VgRes res, Error* e1, Error* e2 )
sewardjde4a1d02002-03-22 01:27:54 +0000249{
njn810086f2002-11-14 12:42:47 +0000250 if (e1->ekind != e2->ekind)
sewardjde4a1d02002-03-22 01:27:54 +0000251 return False;
njn25e49d8e72002-09-23 09:36:25 +0000252 if (!VG_(eq_ExeContext)(res, e1->where, e2->where))
sewardjde4a1d02002-03-22 01:27:54 +0000253 return False;
254
njn810086f2002-11-14 12:42:47 +0000255 switch (e1->ekind) {
sewardjb5f6f512005-03-10 23:59:00 +0000256 // case ThreadErr:
257 // case MutexErr:
258 // vg_assert(VG_(needs).core_errors);
259 // return VG_(tm_error_equal)(res, e1, e2);
sewardjde4a1d02002-03-22 01:27:54 +0000260 default:
njn51d827b2005-05-09 01:02:08 +0000261 if (VG_(needs).tool_errors) {
262 return VG_TDICT_CALL(tool_eq_Error, res, e1, e2);
263 } else {
njn95ec8702004-11-22 16:46:13 +0000264 VG_(printf)("\nUnhandled error type: %u. VG_(needs).tool_errors\n"
njn25e49d8e72002-09-23 09:36:25 +0000265 "probably needs to be set.\n",
njn810086f2002-11-14 12:42:47 +0000266 e1->ekind);
njn67993252004-11-22 18:02:32 +0000267 VG_(tool_panic)("unhandled error type");
njn25e49d8e72002-09-23 09:36:25 +0000268 }
sewardjde4a1d02002-03-22 01:27:54 +0000269 }
270}
271
njnb0eb66e2005-07-10 16:57:24 +0000272static void pp_Error ( Error* err )
sewardjde4a1d02002-03-22 01:27:54 +0000273{
sewardj71bc3cb2005-05-19 00:25:45 +0000274 if (VG_(clo_xml)) {
275 VG_(message)(Vg_UserMsg, "<error>");
sewardjdbada272005-07-02 21:16:30 +0000276 VG_(message)(Vg_UserMsg, " <unique>0x%x</unique>",
277 err->unique);
sewardj71bc3cb2005-05-19 00:25:45 +0000278 VG_(message)(Vg_UserMsg, " <tid>%d</tid>", err->tid);
279 }
280
281 if (!VG_(clo_xml)) {
sewardj71bc3cb2005-05-19 00:25:45 +0000282 if (err->tid > 0 && err->tid != last_tid_printed) {
283 VG_(message)(Vg_UserMsg, "Thread %d:", err->tid );
284 last_tid_printed = err->tid;
285 }
sewardjb5f6f512005-03-10 23:59:00 +0000286 }
njn25e49d8e72002-09-23 09:36:25 +0000287
njn810086f2002-11-14 12:42:47 +0000288 switch (err->ekind) {
sewardjb5f6f512005-03-10 23:59:00 +0000289 // case ThreadErr:
290 // case MutexErr:
291 // vg_assert(VG_(needs).core_errors);
292 // VG_(tm_error_print)(err);
293 // break;
sewardjde4a1d02002-03-22 01:27:54 +0000294 default:
njn95ec8702004-11-22 16:46:13 +0000295 if (VG_(needs).tool_errors)
njn51d827b2005-05-09 01:02:08 +0000296 VG_TDICT_CALL( tool_pp_Error, err );
njn25e49d8e72002-09-23 09:36:25 +0000297 else {
njn95ec8702004-11-22 16:46:13 +0000298 VG_(printf)("\nUnhandled error type: %u. VG_(needs).tool_errors\n"
njn25e49d8e72002-09-23 09:36:25 +0000299 "probably needs to be set?\n",
njn810086f2002-11-14 12:42:47 +0000300 err->ekind);
njn67993252004-11-22 18:02:32 +0000301 VG_(tool_panic)("unhandled error type");
njn25e49d8e72002-09-23 09:36:25 +0000302 }
sewardjde4a1d02002-03-22 01:27:54 +0000303 }
sewardj71bc3cb2005-05-19 00:25:45 +0000304
305 if (VG_(clo_xml))
306 VG_(message)(Vg_UserMsg, "</error>");
sewardjde4a1d02002-03-22 01:27:54 +0000307}
308
nethercote04d0fbc2004-01-26 16:48:06 +0000309/* Figure out if we want to perform a given action for this error, possibly
sewardjde4a1d02002-03-22 01:27:54 +0000310 by asking the user. */
njn43c799e2003-04-08 00:08:52 +0000311Bool VG_(is_action_requested) ( Char* action, Bool* clo )
sewardjde4a1d02002-03-22 01:27:54 +0000312{
313 Char ch, ch2;
314 Int res;
315
njn43c799e2003-04-08 00:08:52 +0000316 if (*clo == False)
sewardjde4a1d02002-03-22 01:27:54 +0000317 return False;
318
319 VG_(message)(Vg_UserMsg, "");
320
321 again:
322 VG_(printf)(
323 "==%d== "
njn43c799e2003-04-08 00:08:52 +0000324 "---- %s ? --- [Return/N/n/Y/y/C/c] ---- ",
325 VG_(getpid)(), action
sewardjde4a1d02002-03-22 01:27:54 +0000326 );
327
sewardj6024b212003-07-13 10:54:33 +0000328 res = VG_(read)(VG_(clo_input_fd), &ch, 1);
sewardjde4a1d02002-03-22 01:27:54 +0000329 if (res != 1) goto ioerror;
330 /* res == 1 */
331 if (ch == '\n') return False;
332 if (ch != 'N' && ch != 'n' && ch != 'Y' && ch != 'y'
333 && ch != 'C' && ch != 'c') goto again;
334
sewardj6024b212003-07-13 10:54:33 +0000335 res = VG_(read)(VG_(clo_input_fd), &ch2, 1);
sewardjde4a1d02002-03-22 01:27:54 +0000336 if (res != 1) goto ioerror;
337 if (ch2 != '\n') goto again;
338
njn43c799e2003-04-08 00:08:52 +0000339 /* No, don't want to do action. */
sewardjde4a1d02002-03-22 01:27:54 +0000340 if (ch == 'n' || ch == 'N') return False;
njn43c799e2003-04-08 00:08:52 +0000341 /* Yes, want to do action. */
sewardjde4a1d02002-03-22 01:27:54 +0000342 if (ch == 'y' || ch == 'Y') return True;
njn43c799e2003-04-08 00:08:52 +0000343 /* No, don't want to do action, and don't ask again either. */
sewardjde4a1d02002-03-22 01:27:54 +0000344 vg_assert(ch == 'c' || ch == 'C');
345
346 ioerror:
njn43c799e2003-04-08 00:08:52 +0000347 *clo = False;
sewardjde4a1d02002-03-22 01:27:54 +0000348 return False;
349}
350
351
sewardjb5f6f512005-03-10 23:59:00 +0000352/* Construct an error */
njn25e49d8e72002-09-23 09:36:25 +0000353static __inline__
njn72718642003-07-24 08:45:32 +0000354void construct_error ( Error* err, ThreadId tid, ErrorKind ekind, Addr a,
355 Char* s, void* extra, ExeContext* where )
sewardjde4a1d02002-03-22 01:27:54 +0000356{
sewardjdbada272005-07-02 21:16:30 +0000357 /* DO NOT MAKE unique_counter NON-STATIC */
358 static UInt unique_counter = 0;
359
njnca82cc02004-11-22 17:18:48 +0000360 tl_assert(tid < VG_N_THREADS);
njn72718642003-07-24 08:45:32 +0000361
njn810086f2002-11-14 12:42:47 +0000362 /* Core-only parts */
sewardjdbada272005-07-02 21:16:30 +0000363 err->unique = unique_counter++;
njn25e49d8e72002-09-23 09:36:25 +0000364 err->next = NULL;
365 err->supp = NULL;
366 err->count = 1;
njn72718642003-07-24 08:45:32 +0000367 err->tid = tid;
njn43c799e2003-04-08 00:08:52 +0000368 if (NULL == where)
njnd01fef72005-03-25 23:35:48 +0000369 err->where = VG_(record_ExeContext)( tid );
njn43c799e2003-04-08 00:08:52 +0000370 else
371 err->where = where;
njn1d6c4bc2002-11-21 13:38:08 +0000372
nethercote996901a2004-08-03 13:29:09 +0000373 /* Tool-relevant parts */
njn810086f2002-11-14 12:42:47 +0000374 err->ekind = ekind;
375 err->addr = a;
njn810086f2002-11-14 12:42:47 +0000376 err->extra = extra;
sewardja6022612003-07-24 23:50:17 +0000377 err->string = s;
378
njn25e49d8e72002-09-23 09:36:25 +0000379 /* sanity... */
njn72718642003-07-24 08:45:32 +0000380 vg_assert( tid < VG_N_THREADS );
njn25e49d8e72002-09-23 09:36:25 +0000381}
382
njn83f9e792005-06-11 05:04:09 +0000383#define ERRTXT_LEN 4096
384
njnf4261312005-03-20 23:45:36 +0000385static void printSuppForIp(UInt n, Addr ip)
386{
njn83f9e792005-06-11 05:04:09 +0000387 static UChar buf[ERRTXT_LEN];
njnf4261312005-03-20 23:45:36 +0000388
njn83f9e792005-06-11 05:04:09 +0000389 if ( VG_(get_fnname_nodemangle) (ip, buf, ERRTXT_LEN) ) {
njnf4261312005-03-20 23:45:36 +0000390 VG_(printf)(" fun:%s\n", buf);
njn83f9e792005-06-11 05:04:09 +0000391 } else if ( VG_(get_objname)(ip, buf, ERRTXT_LEN) ) {
njnf4261312005-03-20 23:45:36 +0000392 VG_(printf)(" obj:%s\n", buf);
393 } else {
njn966d6632005-08-18 15:49:21 +0000394 VG_(printf)(" obj:*\n");
njnf4261312005-03-20 23:45:36 +0000395 }
396}
397
nethercote10d481a2004-01-25 20:33:53 +0000398static void gen_suppression(Error* err)
njn43c799e2003-04-08 00:08:52 +0000399{
njn43c799e2003-04-08 00:08:52 +0000400 ExeContext* ec = VG_(get_error_where)(err);
401 Int stop_at = VG_(clo_backtrace_size);
njn43c799e2003-04-08 00:08:52 +0000402
sewardjb5f6f512005-03-10 23:59:00 +0000403 /* At most VG_MAX_SUPP_CALLERS names */
404 if (stop_at > VG_MAX_SUPP_CALLERS) stop_at = VG_MAX_SUPP_CALLERS;
njn43c799e2003-04-08 00:08:52 +0000405 vg_assert(stop_at > 0);
406
407 VG_(printf)("{\n");
408 VG_(printf)(" <insert a suppression name here>\n");
njn6a230532003-07-21 10:38:23 +0000409
sewardjb5f6f512005-03-10 23:59:00 +0000410 if (ThreadErr == err->ekind || MutexErr == err->ekind) {
njn6a230532003-07-21 10:38:23 +0000411 VG_(printf)(" core:PThread\n");
412
413 } else {
njn51d827b2005-05-09 01:02:08 +0000414 Char* name = VG_TDICT_CALL(tool_get_error_name, err);
njn6a230532003-07-21 10:38:23 +0000415 if (NULL == name) {
416 VG_(message)(Vg_UserMsg,
nethercote137bc552003-11-14 17:47:54 +0000417 "(tool does not allow error to be suppressed)");
njn6a230532003-07-21 10:38:23 +0000418 return;
419 }
420 VG_(printf)(" %s:%s\n", VG_(details).name, name);
njn51d827b2005-05-09 01:02:08 +0000421 VG_TDICT_CALL(tool_print_extra_suppression_info, err);
njn6a230532003-07-21 10:38:23 +0000422 }
njn43c799e2003-04-08 00:08:52 +0000423
njnf4261312005-03-20 23:45:36 +0000424 // Print stack trace elements
njnd01fef72005-03-25 23:35:48 +0000425 VG_(apply_StackTrace)(printSuppForIp, VG_(extract_StackTrace)(ec), stop_at);
njn43c799e2003-04-08 00:08:52 +0000426
427 VG_(printf)("}\n");
428}
429
njnb4aee052003-04-15 14:09:58 +0000430static
nethercote04d0fbc2004-01-26 16:48:06 +0000431void do_actions_on_error(Error* err, Bool allow_db_attach)
njn43c799e2003-04-08 00:08:52 +0000432{
sewardjd153fae2005-01-10 17:24:47 +0000433 Bool still_noisy = True;
434
nethercote04d0fbc2004-01-26 16:48:06 +0000435 /* Perhaps we want a debugger attach at this point? */
436 if (allow_db_attach &&
njnd2b17112005-04-19 04:10:25 +0000437 VG_(is_action_requested)( "Attach to debugger", & VG_(clo_db_attach) ))
438 {
nethercote04d0fbc2004-01-26 16:48:06 +0000439 VG_(printf)("starting debugger\n");
440 VG_(start_debugger)( err->tid );
njnd2b17112005-04-19 04:10:25 +0000441 }
njn43c799e2003-04-08 00:08:52 +0000442 /* Or maybe we want to generate the error's suppression? */
sewardjd153fae2005-01-10 17:24:47 +0000443 if (VG_(clo_gen_suppressions) == 2
444 || (VG_(clo_gen_suppressions) == 1
njnd2b17112005-04-19 04:10:25 +0000445 && VG_(is_action_requested)( "Print suppression", &still_noisy ))
sewardjd153fae2005-01-10 17:24:47 +0000446 ) {
nethercote42602b12004-01-25 19:30:29 +0000447 gen_suppression(err);
sewardjd153fae2005-01-10 17:24:47 +0000448 if (VG_(clo_gen_suppressions) == 1 && !still_noisy)
449 VG_(clo_gen_suppressions) = 0;
njn43c799e2003-04-08 00:08:52 +0000450 }
451}
452
453/* Shared between VG_(maybe_record_error)() and VG_(unique_error)(),
454 just for pretty printing purposes. */
455static Bool is_first_shown_context = True;
456
njn25e49d8e72002-09-23 09:36:25 +0000457/* Top-level entry point to the error management subsystem.
458 All detected errors are notified here; this routine decides if/when the
459 user should see the error. */
njn72718642003-07-24 08:45:32 +0000460void VG_(maybe_record_error) ( ThreadId tid,
njn25e49d8e72002-09-23 09:36:25 +0000461 ErrorKind ekind, Addr a, Char* s, void* extra )
462{
njn810086f2002-11-14 12:42:47 +0000463 Error err;
464 Error* p;
465 Error* p_prev;
njn43c799e2003-04-08 00:08:52 +0000466 UInt extra_size;
njn695c16e2005-03-27 03:40:28 +0000467 VgRes exe_res = Vg_MedRes;
468 static Bool stopping_message = False;
469 static Bool slowdown_message = False;
470 static Int n_errs_shown = 0;
sewardjde4a1d02002-03-22 01:27:54 +0000471
njn14319cc2005-03-13 06:26:22 +0000472 /* After M_COLLECT_NO_ERRORS_AFTER_SHOWN different errors have
473 been found, or M_COLLECT_NO_ERRORS_AFTER_FOUND total errors
sewardjf2537be2002-04-24 21:03:47 +0000474 have been found, just refuse to collect any more. This stops
475 the burden of the error-management system becoming excessive in
476 extremely buggy programs, although it does make it pretty
477 pointless to continue the Valgrind run after this point. */
sewardj2e432902002-06-13 20:44:00 +0000478 if (VG_(clo_error_limit)
njn695c16e2005-03-27 03:40:28 +0000479 && (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN
sewardj8a051722005-06-30 00:10:16 +0000480 || n_errs_found >= M_COLLECT_NO_ERRORS_AFTER_FOUND)
481 && !VG_(clo_xml)) {
sewardjde4a1d02002-03-22 01:27:54 +0000482 if (!stopping_message) {
483 VG_(message)(Vg_UserMsg, "");
sewardjf2537be2002-04-24 21:03:47 +0000484
njn695c16e2005-03-27 03:40:28 +0000485 if (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN) {
sewardjf2537be2002-04-24 21:03:47 +0000486 VG_(message)(Vg_UserMsg,
487 "More than %d different errors detected. "
488 "I'm not reporting any more.",
njn14319cc2005-03-13 06:26:22 +0000489 M_COLLECT_NO_ERRORS_AFTER_SHOWN );
sewardjf2537be2002-04-24 21:03:47 +0000490 } else {
491 VG_(message)(Vg_UserMsg,
492 "More than %d total errors detected. "
493 "I'm not reporting any more.",
njn14319cc2005-03-13 06:26:22 +0000494 M_COLLECT_NO_ERRORS_AFTER_FOUND );
sewardjf2537be2002-04-24 21:03:47 +0000495 }
496
sewardjde4a1d02002-03-22 01:27:54 +0000497 VG_(message)(Vg_UserMsg,
sewardjf2537be2002-04-24 21:03:47 +0000498 "Final error counts will be inaccurate. Go fix your program!");
sewardj72f98ff2002-06-13 17:23:38 +0000499 VG_(message)(Vg_UserMsg,
sewardj2e432902002-06-13 20:44:00 +0000500 "Rerun with --error-limit=no to disable this cutoff. Note");
sewardj72f98ff2002-06-13 17:23:38 +0000501 VG_(message)(Vg_UserMsg,
njn25e49d8e72002-09-23 09:36:25 +0000502 "that errors may occur in your program without prior warning from");
sewardj72f98ff2002-06-13 17:23:38 +0000503 VG_(message)(Vg_UserMsg,
504 "Valgrind, because errors are no longer being displayed.");
sewardjde4a1d02002-03-22 01:27:54 +0000505 VG_(message)(Vg_UserMsg, "");
506 stopping_message = True;
507 }
508 return;
509 }
510
njn14319cc2005-03-13 06:26:22 +0000511 /* After M_COLLECT_ERRORS_SLOWLY_AFTER different errors have
sewardjde4a1d02002-03-22 01:27:54 +0000512 been found, be much more conservative about collecting new
513 ones. */
sewardj8a051722005-06-30 00:10:16 +0000514 if (n_errs_shown >= M_COLLECT_ERRORS_SLOWLY_AFTER
515 && !VG_(clo_xml)) {
njn25e49d8e72002-09-23 09:36:25 +0000516 exe_res = Vg_LowRes;
sewardjde4a1d02002-03-22 01:27:54 +0000517 if (!slowdown_message) {
518 VG_(message)(Vg_UserMsg, "");
519 VG_(message)(Vg_UserMsg,
520 "More than %d errors detected. Subsequent errors",
njn14319cc2005-03-13 06:26:22 +0000521 M_COLLECT_ERRORS_SLOWLY_AFTER);
sewardjde4a1d02002-03-22 01:27:54 +0000522 VG_(message)(Vg_UserMsg,
523 "will still be recorded, but in less detail than before.");
524 slowdown_message = True;
525 }
526 }
527
njn25e49d8e72002-09-23 09:36:25 +0000528 /* Build ourselves the error */
njn72718642003-07-24 08:45:32 +0000529 construct_error ( &err, tid, ekind, a, s, extra, NULL );
sewardjde4a1d02002-03-22 01:27:54 +0000530
531 /* First, see if we've got an error record matching this one. */
njn695c16e2005-03-27 03:40:28 +0000532 p = errors;
sewardjde4a1d02002-03-22 01:27:54 +0000533 p_prev = NULL;
534 while (p != NULL) {
njn810086f2002-11-14 12:42:47 +0000535 if (eq_Error(exe_res, p, &err)) {
sewardjde4a1d02002-03-22 01:27:54 +0000536 /* Found it. */
537 p->count++;
538 if (p->supp != NULL) {
539 /* Deal correctly with suppressed errors. */
540 p->supp->count++;
nethercotef2b11482004-08-02 12:36:01 +0000541 n_errs_suppressed++;
sewardjde4a1d02002-03-22 01:27:54 +0000542 } else {
nethercotef2b11482004-08-02 12:36:01 +0000543 n_errs_found++;
sewardjde4a1d02002-03-22 01:27:54 +0000544 }
545
546 /* Move p to the front of the list so that future searches
547 for it are faster. */
548 if (p_prev != NULL) {
549 vg_assert(p_prev->next == p);
njn695c16e2005-03-27 03:40:28 +0000550 p_prev->next = p->next;
551 p->next = errors;
552 errors = p;
sewardjde4a1d02002-03-22 01:27:54 +0000553 }
sewardj7ebf7c32003-07-24 21:29:40 +0000554
sewardjde4a1d02002-03-22 01:27:54 +0000555 return;
556 }
557 p_prev = p;
558 p = p->next;
559 }
560
561 /* Didn't see it. Copy and add. */
562
njn43c799e2003-04-08 00:08:52 +0000563 /* OK, we're really going to collect it. The context is on the stack and
564 will disappear shortly, so we must copy it. First do the main
njn02bc4b82005-05-15 17:28:26 +0000565 (non-'extra') part.
njn25e49d8e72002-09-23 09:36:25 +0000566
njn02bc4b82005-05-15 17:28:26 +0000567 Then VG_(tdict).tool_update_extra can update the 'extra' part. This
njn51d827b2005-05-09 01:02:08 +0000568 is for when there are more details to fill in which take time to work
569 out but don't affect our earlier decision to include the error -- by
njn25e49d8e72002-09-23 09:36:25 +0000570 postponing those details until now, we avoid the extra work in the
njn810086f2002-11-14 12:42:47 +0000571 case where we ignore the error. Ugly.
njn43c799e2003-04-08 00:08:52 +0000572
njn02bc4b82005-05-15 17:28:26 +0000573 Then, if there is an 'extra' part, copy it too, using the size that
njn51d827b2005-05-09 01:02:08 +0000574 VG_(tdict).tool_update_extra returned. Also allow for people using
575 the void* extra field for a scalar value like an integer.
njn43c799e2003-04-08 00:08:52 +0000576 */
577
578 /* copy main part */
njn810086f2002-11-14 12:42:47 +0000579 p = VG_(arena_malloc)(VG_AR_ERRORS, sizeof(Error));
njn25e49d8e72002-09-23 09:36:25 +0000580 *p = err;
njn43c799e2003-04-08 00:08:52 +0000581
njn02bc4b82005-05-15 17:28:26 +0000582 /* update 'extra' */
sewardjb5f6f512005-03-10 23:59:00 +0000583 switch (ekind) {
584 // case ThreadErr:
585 // case MutexErr:
586 // vg_assert(VG_(needs).core_errors);
587 // extra_size = VG_(tm_error_update_extra)(p);
588 // break;
589 default:
590 vg_assert(VG_(needs).tool_errors);
njn51d827b2005-05-09 01:02:08 +0000591 extra_size = VG_TDICT_CALL(tool_update_extra, p);
sewardjb5f6f512005-03-10 23:59:00 +0000592 break;
593 }
njn43c799e2003-04-08 00:08:52 +0000594
njn02bc4b82005-05-15 17:28:26 +0000595 /* copy block pointed to by 'extra', if there is one */
sewardjb5f6f512005-03-10 23:59:00 +0000596 if (NULL != p->extra && 0 != extra_size) {
597 void* new_extra = VG_(malloc)(extra_size);
598 VG_(memcpy)(new_extra, p->extra, extra_size);
599 p->extra = new_extra;
njn43c799e2003-04-08 00:08:52 +0000600 }
601
njn695c16e2005-03-27 03:40:28 +0000602 p->next = errors;
njn25e49d8e72002-09-23 09:36:25 +0000603 p->supp = is_suppressible_error(&err);
njn695c16e2005-03-27 03:40:28 +0000604 errors = p;
sewardjde4a1d02002-03-22 01:27:54 +0000605 if (p->supp == NULL) {
nethercotef2b11482004-08-02 12:36:01 +0000606 n_errs_found++;
sewardjde4a1d02002-03-22 01:27:54 +0000607 if (!is_first_shown_context)
608 VG_(message)(Vg_UserMsg, "");
njnb0eb66e2005-07-10 16:57:24 +0000609 pp_Error(p);
sewardjde4a1d02002-03-22 01:27:54 +0000610 is_first_shown_context = False;
njn695c16e2005-03-27 03:40:28 +0000611 n_errs_shown++;
nethercote04d0fbc2004-01-26 16:48:06 +0000612 do_actions_on_error(p, /*allow_db_attach*/True);
sewardjde4a1d02002-03-22 01:27:54 +0000613 } else {
nethercotef2b11482004-08-02 12:36:01 +0000614 n_errs_suppressed++;
sewardjde4a1d02002-03-22 01:27:54 +0000615 p->supp->count++;
616 }
617}
618
njn43c799e2003-04-08 00:08:52 +0000619/* Second top-level entry point to the error management subsystem, for
nethercote7cc9c232004-01-21 15:08:04 +0000620 errors that the tool wants to report immediately, eg. because they're
njn43c799e2003-04-08 00:08:52 +0000621 guaranteed to only happen once. This avoids all the recording and
622 comparing stuff. But they can be suppressed; returns True if it is
njn02bc4b82005-05-15 17:28:26 +0000623 suppressed. Bool 'print_error' dictates whether to print the error.
624 Bool 'count_error' dictates whether to count the error in n_errs_found.
njn47363ab2003-04-21 13:24:40 +0000625*/
njn72718642003-07-24 08:45:32 +0000626Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind, Addr a, Char* s,
njn3e884182003-04-15 13:03:23 +0000627 void* extra, ExeContext* where, Bool print_error,
nethercote04d0fbc2004-01-26 16:48:06 +0000628 Bool allow_db_attach, Bool count_error )
njn43c799e2003-04-08 00:08:52 +0000629{
630 Error err;
631
632 /* Build ourselves the error */
njn72718642003-07-24 08:45:32 +0000633 construct_error ( &err, tid, ekind, a, s, extra, where );
njn43c799e2003-04-08 00:08:52 +0000634
635 /* Unless it's suppressed, we're going to show it. Don't need to make
636 a copy, because it's only temporary anyway.
637
njn02bc4b82005-05-15 17:28:26 +0000638 Then update the 'extra' part with VG_(tdict).tool_update_extra),
njn51d827b2005-05-09 01:02:08 +0000639 because that can have an affect on whether it's suppressed. Ignore
640 the size return value of VG_(tdict).tool_update_extra, because we're
njn02bc4b82005-05-15 17:28:26 +0000641 not copying 'extra'. */
njn51d827b2005-05-09 01:02:08 +0000642 (void)VG_TDICT_CALL(tool_update_extra, &err);
njn43c799e2003-04-08 00:08:52 +0000643
644 if (NULL == is_suppressible_error(&err)) {
njn47363ab2003-04-21 13:24:40 +0000645 if (count_error)
nethercotef2b11482004-08-02 12:36:01 +0000646 n_errs_found++;
njn43c799e2003-04-08 00:08:52 +0000647
648 if (print_error) {
649 if (!is_first_shown_context)
650 VG_(message)(Vg_UserMsg, "");
njnb0eb66e2005-07-10 16:57:24 +0000651 pp_Error(&err);
njn43c799e2003-04-08 00:08:52 +0000652 is_first_shown_context = False;
653 }
nethercote04d0fbc2004-01-26 16:48:06 +0000654 do_actions_on_error(&err, allow_db_attach);
njn43c799e2003-04-08 00:08:52 +0000655
656 return False;
657
658 } else {
nethercotef2b11482004-08-02 12:36:01 +0000659 n_errs_suppressed++;
njn43c799e2003-04-08 00:08:52 +0000660 return True;
661 }
662}
663
sewardjde4a1d02002-03-22 01:27:54 +0000664
sewardjde4a1d02002-03-22 01:27:54 +0000665/*------------------------------------------------------------*/
666/*--- Exported fns ---*/
667/*------------------------------------------------------------*/
668
sewardj71bc3cb2005-05-19 00:25:45 +0000669/* Show the used suppressions. Returns False if no suppression
670 got used. */
671static Bool show_used_suppressions ( void )
672{
673 Supp *su;
674 Bool any_supp;
675
sewardj7c9e57c2005-05-24 14:21:45 +0000676 if (VG_(clo_xml))
677 VG_(message)(Vg_DebugMsg, "<suppcounts>");
678
sewardj71bc3cb2005-05-19 00:25:45 +0000679 any_supp = False;
680 for (su = suppressions; su != NULL; su = su->next) {
681 if (su->count <= 0)
682 continue;
683 any_supp = True;
684 if (VG_(clo_xml)) {
685 VG_(message)(Vg_DebugMsg,
sewardj753673f2005-08-09 22:03:08 +0000686 " <pair>\n"
687 " <count>%d</count>\n"
688 " <name>%t</name>\n"
689 " </pair>",
sewardj71bc3cb2005-05-19 00:25:45 +0000690 su->count, su->sname);
691 } else {
692 VG_(message)(Vg_DebugMsg, "supp: %4d %s", su->count, su->sname);
693 }
694 }
695
sewardj7c9e57c2005-05-24 14:21:45 +0000696 if (VG_(clo_xml))
sewardj8665d8e2005-06-01 17:35:23 +0000697 VG_(message)(Vg_DebugMsg, "</suppcounts>");
sewardj7c9e57c2005-05-24 14:21:45 +0000698
sewardj71bc3cb2005-05-19 00:25:45 +0000699 return any_supp;
700}
701
702
sewardj9f297ca2005-05-20 02:29:52 +0000703/* Show all the errors that occurred, and possibly also the
704 suppressions used. */
sewardjde4a1d02002-03-22 01:27:54 +0000705void VG_(show_all_errors) ( void )
706{
njn810086f2002-11-14 12:42:47 +0000707 Int i, n_min;
708 Int n_err_contexts, n_supp_contexts;
709 Error *p, *p_min;
710 Supp *su;
711 Bool any_supp;
sewardjde4a1d02002-03-22 01:27:54 +0000712
713 if (VG_(clo_verbosity) == 0)
714 return;
715
716 n_err_contexts = 0;
njn695c16e2005-03-27 03:40:28 +0000717 for (p = errors; p != NULL; p = p->next) {
sewardjde4a1d02002-03-22 01:27:54 +0000718 if (p->supp == NULL)
719 n_err_contexts++;
720 }
721
722 n_supp_contexts = 0;
njn695c16e2005-03-27 03:40:28 +0000723 for (su = suppressions; su != NULL; su = su->next) {
sewardjde4a1d02002-03-22 01:27:54 +0000724 if (su->count > 0)
725 n_supp_contexts++;
726 }
sewardj71bc3cb2005-05-19 00:25:45 +0000727
728 /* If we're printing XML, just show the suppressions and stop.
729 */
730 if (VG_(clo_xml)) {
731 (void)show_used_suppressions();
732 return;
733 }
734
735 /* We only get here if not printing XML. */
sewardjde4a1d02002-03-22 01:27:54 +0000736 VG_(message)(Vg_UserMsg,
737 "ERROR SUMMARY: "
738 "%d errors from %d contexts (suppressed: %d from %d)",
nethercotef2b11482004-08-02 12:36:01 +0000739 n_errs_found, n_err_contexts,
740 n_errs_suppressed, n_supp_contexts );
sewardjde4a1d02002-03-22 01:27:54 +0000741
742 if (VG_(clo_verbosity) <= 1)
743 return;
744
745 /* Print the contexts in order of increasing error count. */
746 for (i = 0; i < n_err_contexts; i++) {
747 n_min = (1 << 30) - 1;
748 p_min = NULL;
njn695c16e2005-03-27 03:40:28 +0000749 for (p = errors; p != NULL; p = p->next) {
sewardjde4a1d02002-03-22 01:27:54 +0000750 if (p->supp != NULL) continue;
751 if (p->count < n_min) {
752 n_min = p->count;
753 p_min = p;
754 }
755 }
njn67993252004-11-22 18:02:32 +0000756 if (p_min == NULL) VG_(tool_panic)("show_all_errors()");
sewardjde4a1d02002-03-22 01:27:54 +0000757
758 VG_(message)(Vg_UserMsg, "");
759 VG_(message)(Vg_UserMsg, "%d errors in context %d of %d:",
760 p_min->count,
761 i+1, n_err_contexts);
njnb0eb66e2005-07-10 16:57:24 +0000762 pp_Error( p_min );
sewardjde4a1d02002-03-22 01:27:54 +0000763
764 if ((i+1 == VG_(clo_dump_error))) {
njnd01fef72005-03-25 23:35:48 +0000765 StackTrace ips = VG_(extract_StackTrace)(p_min->where);
sewardjfa8ec112005-01-19 11:55:34 +0000766 VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to debugging*/,
njn394213a2005-06-19 18:38:24 +0000767 ips[0], /*debugging*/True, 0xFE/*verbosity*/,
768 /*bbs_done*/0);
sewardjde4a1d02002-03-22 01:27:54 +0000769 }
770
771 p_min->count = 1 << 30;
772 }
773
774 if (n_supp_contexts > 0)
775 VG_(message)(Vg_DebugMsg, "");
sewardj71bc3cb2005-05-19 00:25:45 +0000776 any_supp = show_used_suppressions();
sewardjde4a1d02002-03-22 01:27:54 +0000777
778 if (n_err_contexts > 0) {
779 if (any_supp)
780 VG_(message)(Vg_UserMsg, "");
781 VG_(message)(Vg_UserMsg,
782 "IN SUMMARY: "
783 "%d errors from %d contexts (suppressed: %d from %d)",
nethercotef2b11482004-08-02 12:36:01 +0000784 n_errs_found, n_err_contexts, n_errs_suppressed,
sewardjde4a1d02002-03-22 01:27:54 +0000785 n_supp_contexts );
786 VG_(message)(Vg_UserMsg, "");
787 }
788}
789
sewardj9f297ca2005-05-20 02:29:52 +0000790
791/* Show occurrence counts of all errors, in XML form. */
792void VG_(show_error_counts_as_XML) ( void )
793{
794 Error* err;
795 VG_(message)(Vg_UserMsg, "<errorcounts>");
796 for (err = errors; err != NULL; err = err->next) {
797 if (err->supp != NULL)
798 continue;
799 if (err->count <= 0)
800 continue;
801 VG_(message)(
sewardj753673f2005-08-09 22:03:08 +0000802 Vg_UserMsg, " <pair>\n"
803 " <count>%d</count>\n"
cerion3a24e722005-08-09 22:34:18 +0000804 " <unique>0x%x</unique>\n"
sewardj753673f2005-08-09 22:03:08 +0000805 " </pair>",
sewardj39618202005-08-09 21:50:18 +0000806 err->count, err->unique
sewardj9f297ca2005-05-20 02:29:52 +0000807 );
808 }
809 VG_(message)(Vg_UserMsg, "</errorcounts>");
810}
811
812
sewardjde4a1d02002-03-22 01:27:54 +0000813/*------------------------------------------------------------*/
814/*--- Standard suppressions ---*/
815/*------------------------------------------------------------*/
816
817/* Get a non-blank, non-comment line of at most nBuf chars from fd.
818 Skips leading spaces on the line. Return True if EOF was hit instead.
819*/
njn4ba5a792002-09-30 10:23:54 +0000820Bool VG_(get_line) ( Int fd, Char* buf, Int nBuf )
sewardjde4a1d02002-03-22 01:27:54 +0000821{
822 Char ch;
823 Int n, i;
824 while (True) {
825 /* First, read until a non-blank char appears. */
826 while (True) {
827 n = VG_(read)(fd, &ch, 1);
njn0c0f32a2005-03-26 04:14:01 +0000828 if (n == 1 && !VG_(isspace)(ch)) break;
sewardjde4a1d02002-03-22 01:27:54 +0000829 if (n == 0) return True;
830 }
831
832 /* Now, read the line into buf. */
833 i = 0;
834 buf[i++] = ch; buf[i] = 0;
835 while (True) {
836 n = VG_(read)(fd, &ch, 1);
837 if (n == 0) return False; /* the next call will return True */
838 if (ch == '\n') break;
839 if (i > 0 && i == nBuf-1) i--;
840 buf[i++] = ch; buf[i] = 0;
841 }
njn0c0f32a2005-03-26 04:14:01 +0000842 while (i > 1 && VG_(isspace)(buf[i-1])) {
sewardjde4a1d02002-03-22 01:27:54 +0000843 i--; buf[i] = 0;
844 };
845
njn02bc4b82005-05-15 17:28:26 +0000846 /* VG_(printf)("The line is '%s'\n", buf); */
sewardjde4a1d02002-03-22 01:27:54 +0000847 /* Ok, we have a line. If a non-comment line, return.
848 If a comment line, start all over again. */
849 if (buf[0] != '#') return False;
850 }
851}
852
853
854/* *p_caller contains the raw name of a caller, supposedly either
855 fun:some_function_name or
856 obj:some_object_name.
857 Set *p_ty accordingly and advance *p_caller over the descriptor
858 (fun: or obj:) part.
859 Returns False if failed.
860*/
sewardjb5f6f512005-03-10 23:59:00 +0000861static Bool setLocationTy ( SuppLoc* p )
sewardjde4a1d02002-03-22 01:27:54 +0000862{
sewardjb5f6f512005-03-10 23:59:00 +0000863 if (VG_(strncmp)(p->name, "fun:", 4) == 0) {
864 p->name += 4;
865 p->ty = FunName;
sewardjde4a1d02002-03-22 01:27:54 +0000866 return True;
867 }
sewardjb5f6f512005-03-10 23:59:00 +0000868 if (VG_(strncmp)(p->name, "obj:", 4) == 0) {
869 p->name += 4;
870 p->ty = ObjName;
sewardjde4a1d02002-03-22 01:27:54 +0000871 return True;
872 }
873 VG_(printf)("location should start with fun: or obj:\n");
874 return False;
875}
876
877
nethercote7cc9c232004-01-21 15:08:04 +0000878/* Look for "tool" in a string like "tool1,tool2,tool3" */
njn11cc9252002-10-07 14:42:59 +0000879static __inline__
nethercote7cc9c232004-01-21 15:08:04 +0000880Bool tool_name_present(Char *name, Char *names)
njn11cc9252002-10-07 14:42:59 +0000881{
882 Bool found;
883 Char *s = NULL; /* Shut gcc up */
884 Int len = VG_(strlen)(name);
885
886 found = (NULL != (s = VG_(strstr)(names, name)) &&
887 (s == names || *(s-1) == ',') &&
888 (*(s+len) == ',' || *(s+len) == '\0')
889 );
890
891 return found;
892}
893
njn695c16e2005-03-27 03:40:28 +0000894/* Read suppressions from the file specified in VG_(clo_suppressions)
sewardjde4a1d02002-03-22 01:27:54 +0000895 and place them in the suppressions list. If there's any difficulty
896 doing this, just give up -- there's no point in trying to recover.
897*/
sewardjde4a1d02002-03-22 01:27:54 +0000898static void load_one_suppressions_file ( Char* filename )
899{
900# define N_BUF 200
sewardj92645592005-07-23 09:18:34 +0000901 SysRes sres;
902 Int fd, i;
903 Bool eof;
904 Char buf[N_BUF+1];
905 Char* tool_names;
906 Char* supp_name;
907 Char* err_str = NULL;
sewardjb5f6f512005-03-10 23:59:00 +0000908 SuppLoc tmp_callers[VG_MAX_SUPP_CALLERS];
njnc40c3a82002-10-02 11:02:27 +0000909
sewardj92645592005-07-23 09:18:34 +0000910 fd = -1;
911 sres = VG_(open)( filename, VKI_O_RDONLY, 0 );
912 if (sres.isError) {
sewardjf349d552005-11-14 17:01:01 +0000913 if (VG_(clo_xml))
914 VG_(message)(Vg_UserMsg, "</valgrindoutput>\n");
njn02bc4b82005-05-15 17:28:26 +0000915 VG_(message)(Vg_UserMsg, "FATAL: can't open suppressions file '%s'",
sewardjde4a1d02002-03-22 01:27:54 +0000916 filename );
917 VG_(exit)(1);
918 }
sewardj92645592005-07-23 09:18:34 +0000919 fd = sres.val;
sewardjde4a1d02002-03-22 01:27:54 +0000920
sewardj92645592005-07-23 09:18:34 +0000921# define BOMB(S) { err_str = S; goto syntax_error; }
sewardjb5f6f512005-03-10 23:59:00 +0000922
sewardjde4a1d02002-03-22 01:27:54 +0000923 while (True) {
nethercote7cc9c232004-01-21 15:08:04 +0000924 /* Assign and initialise the two suppression halves (core and tool) */
njn810086f2002-11-14 12:42:47 +0000925 Supp* supp;
926 supp = VG_(arena_malloc)(VG_AR_CORE, sizeof(Supp));
sewardjde4a1d02002-03-22 01:27:54 +0000927 supp->count = 0;
sewardjb5f6f512005-03-10 23:59:00 +0000928
929 // Initialise temporary reading-in buffer.
930 for (i = 0; i < VG_MAX_SUPP_CALLERS; i++) {
931 tmp_callers[i].ty = NoName;
932 tmp_callers[i].name = NULL;
933 }
934
njn810086f2002-11-14 12:42:47 +0000935 supp->string = supp->extra = NULL;
sewardjde4a1d02002-03-22 01:27:54 +0000936
njn4ba5a792002-09-30 10:23:54 +0000937 eof = VG_(get_line) ( fd, buf, N_BUF );
sewardjde4a1d02002-03-22 01:27:54 +0000938 if (eof) break;
939
sewardjb5f6f512005-03-10 23:59:00 +0000940 if (!VG_STREQ(buf, "{")) BOMB("expected '{' or end-of-file");
sewardjde4a1d02002-03-22 01:27:54 +0000941
njn4ba5a792002-09-30 10:23:54 +0000942 eof = VG_(get_line) ( fd, buf, N_BUF );
sewardjb5f6f512005-03-10 23:59:00 +0000943
944 if (eof || VG_STREQ(buf, "}")) BOMB("unexpected '}'");
945
njn25e49d8e72002-09-23 09:36:25 +0000946 supp->sname = VG_(arena_strdup)(VG_AR_CORE, buf);
sewardjde4a1d02002-03-22 01:27:54 +0000947
njn4ba5a792002-09-30 10:23:54 +0000948 eof = VG_(get_line) ( fd, buf, N_BUF );
njn25e49d8e72002-09-23 09:36:25 +0000949
sewardjb5f6f512005-03-10 23:59:00 +0000950 if (eof) BOMB("unexpected end-of-file");
sewardjde4a1d02002-03-22 01:27:54 +0000951
njn94065fd2004-11-22 19:26:27 +0000952 /* Check it has the "tool1,tool2,...:supp" form (look for ':') */
njnc40c3a82002-10-02 11:02:27 +0000953 i = 0;
954 while (True) {
955 if (buf[i] == ':') break;
sewardjb5f6f512005-03-10 23:59:00 +0000956 if (buf[i] == '\0') BOMB("malformed 'tool1,tool2,...:supp' line");
njnc40c3a82002-10-02 11:02:27 +0000957 i++;
njn25e49d8e72002-09-23 09:36:25 +0000958 }
njnc40c3a82002-10-02 11:02:27 +0000959 buf[i] = '\0'; /* Replace ':', splitting into two strings */
960
nethercote7cc9c232004-01-21 15:08:04 +0000961 tool_names = & buf[0];
njn11cc9252002-10-07 14:42:59 +0000962 supp_name = & buf[i+1];
njnc40c3a82002-10-02 11:02:27 +0000963
nethercote7cc9c232004-01-21 15:08:04 +0000964 if (VG_(needs).core_errors && tool_name_present("core", tool_names))
njnc40c3a82002-10-02 11:02:27 +0000965 {
sewardjb5f6f512005-03-10 23:59:00 +0000966 // A core suppression
njn43c799e2003-04-08 00:08:52 +0000967 if (VG_STREQ(supp_name, "PThread"))
njn810086f2002-11-14 12:42:47 +0000968 supp->skind = PThreadSupp;
njnc40c3a82002-10-02 11:02:27 +0000969 else
sewardjb5f6f512005-03-10 23:59:00 +0000970 BOMB("unknown core suppression type");
njnc40c3a82002-10-02 11:02:27 +0000971 }
njn95ec8702004-11-22 16:46:13 +0000972 else if (VG_(needs).tool_errors &&
nethercote7cc9c232004-01-21 15:08:04 +0000973 tool_name_present(VG_(details).name, tool_names))
njnc40c3a82002-10-02 11:02:27 +0000974 {
sewardjb5f6f512005-03-10 23:59:00 +0000975 // A tool suppression
njn51d827b2005-05-09 01:02:08 +0000976 if (VG_TDICT_CALL(tool_recognised_suppression, supp_name, supp)) {
njn810086f2002-11-14 12:42:47 +0000977 /* Do nothing, function fills in supp->skind */
sewardjb5f6f512005-03-10 23:59:00 +0000978 } else {
979 BOMB("unknown tool suppression type");
980 }
njnc40c3a82002-10-02 11:02:27 +0000981 }
njn25e49d8e72002-09-23 09:36:25 +0000982 else {
sewardjb5f6f512005-03-10 23:59:00 +0000983 // Ignore rest of suppression
njn25e49d8e72002-09-23 09:36:25 +0000984 while (True) {
njn4ba5a792002-09-30 10:23:54 +0000985 eof = VG_(get_line) ( fd, buf, N_BUF );
sewardjb5f6f512005-03-10 23:59:00 +0000986 if (eof) BOMB("unexpected end-of-file");
njn43c799e2003-04-08 00:08:52 +0000987 if (VG_STREQ(buf, "}"))
njn25e49d8e72002-09-23 09:36:25 +0000988 break;
989 }
990 continue;
sewardjde4a1d02002-03-22 01:27:54 +0000991 }
992
njn95ec8702004-11-22 16:46:13 +0000993 if (VG_(needs).tool_errors &&
njn51d827b2005-05-09 01:02:08 +0000994 !VG_TDICT_CALL(tool_read_extra_suppression_info, fd, buf, N_BUF, supp))
sewardjb5f6f512005-03-10 23:59:00 +0000995 {
996 BOMB("bad or missing extra suppression info");
sewardjde4a1d02002-03-22 01:27:54 +0000997 }
998
sewardjb5f6f512005-03-10 23:59:00 +0000999 i = 0;
1000 while (True) {
1001 eof = VG_(get_line) ( fd, buf, N_BUF );
1002 if (eof)
1003 BOMB("unexpected end-of-file");
1004 if (VG_STREQ(buf, "}")) {
1005 if (i > 0) {
1006 break;
1007 } else {
1008 BOMB("missing stack trace");
1009 }
1010 }
1011 if (i == VG_MAX_SUPP_CALLERS)
1012 BOMB("too many callers in stack trace");
1013 if (i > 0 && i >= VG_(clo_backtrace_size))
1014 break;
1015 tmp_callers[i].name = VG_(arena_strdup)(VG_AR_CORE, buf);
1016 if (!setLocationTy(&(tmp_callers[i])))
1017 BOMB("location should start with 'fun:' or 'obj:'");
1018 i++;
1019 }
1020
1021 // If the num callers is >= VG_(clo_backtrace_size), ignore any extra
1022 // lines and grab the '}'.
sewardj57a8f5f2003-07-06 01:40:11 +00001023 if (!VG_STREQ(buf, "}")) {
sewardjb5f6f512005-03-10 23:59:00 +00001024 do {
1025 eof = VG_(get_line) ( fd, buf, N_BUF );
1026 } while (!eof && !VG_STREQ(buf, "}"));
1027 }
1028
1029 // Copy tmp_callers[] into supp->callers[]
1030 supp->n_callers = i;
1031 supp->callers = VG_(arena_malloc)(VG_AR_CORE, i*sizeof(SuppLoc));
1032 for (i = 0; i < supp->n_callers; i++) {
1033 supp->callers[i] = tmp_callers[i];
sewardj57a8f5f2003-07-06 01:40:11 +00001034 }
1035
njn695c16e2005-03-27 03:40:28 +00001036 supp->next = suppressions;
1037 suppressions = supp;
sewardjde4a1d02002-03-22 01:27:54 +00001038 }
sewardjde4a1d02002-03-22 01:27:54 +00001039 VG_(close)(fd);
1040 return;
1041
1042 syntax_error:
sewardjf349d552005-11-14 17:01:01 +00001043 if (VG_(clo_xml))
1044 VG_(message)(Vg_UserMsg, "</valgrindoutput>\n");
sewardjb5f6f512005-03-10 23:59:00 +00001045 VG_(message)(Vg_UserMsg,
njn02bc4b82005-05-15 17:28:26 +00001046 "FATAL: in suppressions file '%s': %s", filename, err_str );
sewardjb5f6f512005-03-10 23:59:00 +00001047
sewardjde4a1d02002-03-22 01:27:54 +00001048 VG_(close)(fd);
1049 VG_(message)(Vg_UserMsg, "exiting now.");
nethercote8ed8a892004-11-08 13:24:25 +00001050 VG_(exit)(1);
sewardjde4a1d02002-03-22 01:27:54 +00001051
sewardjb5f6f512005-03-10 23:59:00 +00001052# undef BOMB
sewardjde4a1d02002-03-22 01:27:54 +00001053# undef N_BUF
1054}
1055
1056
1057void VG_(load_suppressions) ( void )
1058{
1059 Int i;
njn695c16e2005-03-27 03:40:28 +00001060 suppressions = NULL;
sewardjde4a1d02002-03-22 01:27:54 +00001061 for (i = 0; i < VG_(clo_n_suppressions); i++) {
1062 if (VG_(clo_verbosity) > 1) {
njn3f04d242005-03-20 18:21:14 +00001063 VG_(message)(Vg_DebugMsg, "Reading suppressions file: %s",
1064 VG_(clo_suppressions)[i] );
sewardjde4a1d02002-03-22 01:27:54 +00001065 }
1066 load_one_suppressions_file( VG_(clo_suppressions)[i] );
1067 }
1068}
1069
sewardjb5f6f512005-03-10 23:59:00 +00001070static
njn810086f2002-11-14 12:42:47 +00001071Bool supp_matches_error(Supp* su, Error* err)
njn25e49d8e72002-09-23 09:36:25 +00001072{
njn810086f2002-11-14 12:42:47 +00001073 switch (su->skind) {
njn25e49d8e72002-09-23 09:36:25 +00001074 case PThreadSupp:
sewardjb5f6f512005-03-10 23:59:00 +00001075 return (err->ekind == ThreadErr || err->ekind == MutexErr);
njn25e49d8e72002-09-23 09:36:25 +00001076 default:
njn95ec8702004-11-22 16:46:13 +00001077 if (VG_(needs).tool_errors) {
njn51d827b2005-05-09 01:02:08 +00001078 return VG_TDICT_CALL(tool_error_matches_suppression, err, su);
njn25e49d8e72002-09-23 09:36:25 +00001079 } else {
1080 VG_(printf)(
njn95ec8702004-11-22 16:46:13 +00001081 "\nUnhandled suppression type: %u. VG_(needs).tool_errors\n"
njn25e49d8e72002-09-23 09:36:25 +00001082 "probably needs to be set.\n",
njn810086f2002-11-14 12:42:47 +00001083 err->ekind);
njn67993252004-11-22 18:02:32 +00001084 VG_(tool_panic)("unhandled suppression type");
njn25e49d8e72002-09-23 09:36:25 +00001085 }
1086 }
1087}
1088
sewardjb5f6f512005-03-10 23:59:00 +00001089static
1090Bool supp_matches_callers(Error* err, Supp* su)
njn25e49d8e72002-09-23 09:36:25 +00001091{
1092 Int i;
njn83f9e792005-06-11 05:04:09 +00001093 Char caller_name[ERRTXT_LEN];
njnd01fef72005-03-25 23:35:48 +00001094 StackTrace ips = VG_(extract_StackTrace)(err->where);
njn25e49d8e72002-09-23 09:36:25 +00001095
sewardjb5f6f512005-03-10 23:59:00 +00001096 for (i = 0; i < su->n_callers; i++) {
njnd01fef72005-03-25 23:35:48 +00001097 Addr a = ips[i];
sewardjb5f6f512005-03-10 23:59:00 +00001098 vg_assert(su->callers[i].name != NULL);
njn966d6632005-08-18 15:49:21 +00001099 // The string to be used in the unknown case ("???") can be anything
1100 // that couldn't be a valid function or objname. --gen-suppressions
1101 // prints 'obj:*' for such an entry, which will match any string we
1102 // use.
sewardjb5f6f512005-03-10 23:59:00 +00001103 switch (su->callers[i].ty) {
1104 case ObjName:
njn83f9e792005-06-11 05:04:09 +00001105 if (!VG_(get_objname)(a, caller_name, ERRTXT_LEN))
njn966d6632005-08-18 15:49:21 +00001106 VG_(strcpy)(caller_name, "???");
sewardjb5f6f512005-03-10 23:59:00 +00001107 break;
1108
1109 case FunName:
1110 // Nb: mangled names used in suppressions
njn83f9e792005-06-11 05:04:09 +00001111 if (!VG_(get_fnname_nodemangle)(a, caller_name, ERRTXT_LEN))
njn966d6632005-08-18 15:49:21 +00001112 VG_(strcpy)(caller_name, "???");
sewardjb5f6f512005-03-10 23:59:00 +00001113 break;
njn67993252004-11-22 18:02:32 +00001114 default: VG_(tool_panic)("supp_matches_callers");
njn25e49d8e72002-09-23 09:36:25 +00001115 }
sewardjb5f6f512005-03-10 23:59:00 +00001116 if (!VG_(string_match)(su->callers[i].name, caller_name))
1117 return False;
njn25e49d8e72002-09-23 09:36:25 +00001118 }
1119
1120 /* If we reach here, it's a match */
1121 return True;
1122}
sewardjde4a1d02002-03-22 01:27:54 +00001123
njn810086f2002-11-14 12:42:47 +00001124/* Does an error context match a suppression? ie is this a suppressible
1125 error? If so, return a pointer to the Supp record, otherwise NULL.
njn25e49d8e72002-09-23 09:36:25 +00001126 Tries to minimise the number of symbol searches since they are expensive.
sewardjde4a1d02002-03-22 01:27:54 +00001127*/
njn810086f2002-11-14 12:42:47 +00001128static Supp* is_suppressible_error ( Error* err )
sewardjde4a1d02002-03-22 01:27:54 +00001129{
njn810086f2002-11-14 12:42:47 +00001130 Supp* su;
sewardjde4a1d02002-03-22 01:27:54 +00001131
sewardjde4a1d02002-03-22 01:27:54 +00001132 /* See if the error context matches any suppression. */
njn695c16e2005-03-27 03:40:28 +00001133 for (su = suppressions; su != NULL; su = su->next) {
njn25e49d8e72002-09-23 09:36:25 +00001134 if (supp_matches_error(su, err) &&
sewardjb5f6f512005-03-10 23:59:00 +00001135 supp_matches_callers(err, su))
1136 {
njn25e49d8e72002-09-23 09:36:25 +00001137 return su;
sewardjde4a1d02002-03-22 01:27:54 +00001138 }
sewardjde4a1d02002-03-22 01:27:54 +00001139 }
njn25e49d8e72002-09-23 09:36:25 +00001140 return NULL; /* no matches */
sewardjde4a1d02002-03-22 01:27:54 +00001141}
1142
sewardjde4a1d02002-03-22 01:27:54 +00001143/*--------------------------------------------------------------------*/
njneb8896b2005-06-04 20:03:55 +00001144/*--- end ---*/
sewardjde4a1d02002-03-22 01:27:54 +00001145/*--------------------------------------------------------------------*/