blob: fd900ee660064be1241f2662971ef9c3f25204a8 [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
Elliott Hughesed398002017-06-21 14:41:24 -070010 Copyright (C) 2000-2017 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"
sewardj4cfea4f2006-10-14 19:26:10 +000032#include "pub_core_vki.h"
njn24a6efb2005-06-20 03:36:51 +000033#include "pub_core_threadstate.h" // For VG_N_THREADS
njnea27e462005-05-31 02:38:09 +000034#include "pub_core_debuginfo.h"
philippe5ab7ce82014-06-24 20:48:25 +000035#include "pub_core_debuglog.h"
njnd2b17112005-04-19 04:10:25 +000036#include "pub_core_errormgr.h"
njnd01fef72005-03-25 23:35:48 +000037#include "pub_core_execontext.h"
sewardj3b290482011-05-06 21:02:55 +000038#include "pub_core_gdbserver.h"
njn97405b22005-06-02 03:39:33 +000039#include "pub_core_libcbase.h"
njn132bfcc2005-06-04 19:16:06 +000040#include "pub_core_libcassert.h"
njneb8896b2005-06-04 20:03:55 +000041#include "pub_core_libcfile.h"
njn36a20fa2005-06-03 03:08:39 +000042#include "pub_core_libcprint.h"
njn24a6efb2005-06-20 03:36:51 +000043#include "pub_core_libcproc.h" // For VG_(getpid)()
sewardjd7a02db2008-12-12 08:07:49 +000044#include "pub_core_seqmatch.h"
njnaf1d7df2005-06-11 01:31:52 +000045#include "pub_core_mallocfree.h"
njn20242342005-05-16 23:31:24 +000046#include "pub_core_options.h"
njnd0d7c1f2005-06-21 00:33:19 +000047#include "pub_core_stacktrace.h"
njn43b9a8a2005-05-10 04:37:01 +000048#include "pub_core_tooliface.h"
njn24a6efb2005-06-20 03:36:51 +000049#include "pub_core_translate.h" // for VG_(translate)()
sewardj588adef2009-08-15 22:41:51 +000050#include "pub_core_xarray.h" // VG_(xaprintf) et al
sewardjde4a1d02002-03-22 01:27:54 +000051
philippe5ab7ce82014-06-24 20:48:25 +000052#define DEBUG_ERRORMGR 0 // set to 1 for heavyweight tracing
53
sewardjde4a1d02002-03-22 01:27:54 +000054/*------------------------------------------------------------*/
njn25e49d8e72002-09-23 09:36:25 +000055/*--- Globals ---*/
sewardjde4a1d02002-03-22 01:27:54 +000056/*------------------------------------------------------------*/
57
njn14319cc2005-03-13 06:26:22 +000058/* After this many different unsuppressed errors have been observed,
59 be more conservative about collecting new ones. */
sewardj1d1a2262005-10-20 01:57:29 +000060#define M_COLLECT_ERRORS_SLOWLY_AFTER 100
njn14319cc2005-03-13 06:26:22 +000061
62/* After this many different unsuppressed errors have been observed,
63 stop collecting errors at all, and tell the user their program is
64 evidently a steaming pile of camel dung. */
sewardj1d1a2262005-10-20 01:57:29 +000065#define M_COLLECT_NO_ERRORS_AFTER_SHOWN 1000
njn14319cc2005-03-13 06:26:22 +000066
67/* After this many total errors have been observed, stop collecting
68 errors at all. Counterpart to M_COLLECT_NO_ERRORS_AFTER_SHOWN. */
sewardj513646f2006-05-12 23:12:30 +000069#define M_COLLECT_NO_ERRORS_AFTER_FOUND 10000000
njn14319cc2005-03-13 06:26:22 +000070
sewardjde4a1d02002-03-22 01:27:54 +000071/* The list of error contexts found, both suppressed and unsuppressed.
72 Initially empty, and grows as errors are detected. */
njn695c16e2005-03-27 03:40:28 +000073static Error* errors = NULL;
sewardjde4a1d02002-03-22 01:27:54 +000074
75/* The list of suppression directives, as read from the specified
sewardj8a7d4e42006-10-17 01:41:17 +000076 suppressions file. Note that the list gets rearranged as a result
77 of the searches done by is_suppressible_error(). */
njn695c16e2005-03-27 03:40:28 +000078static Supp* suppressions = NULL;
sewardjde4a1d02002-03-22 01:27:54 +000079
80/* Running count of unsuppressed errors detected. */
nethercotef2b11482004-08-02 12:36:01 +000081static UInt n_errs_found = 0;
sewardjde4a1d02002-03-22 01:27:54 +000082
83/* Running count of suppressed errors detected. */
nethercotef2b11482004-08-02 12:36:01 +000084static UInt n_errs_suppressed = 0;
sewardjde4a1d02002-03-22 01:27:54 +000085
philippebaf69642012-02-15 22:29:30 +000086/* Running count of errors shown. */
87static UInt n_errs_shown = 0;
88
njn606a4ae2009-08-11 00:52:40 +000089/* Running count of unsuppressed error contexts. */
90static UInt n_err_contexts = 0;
91
92/* Running count of suppressed error contexts. */
93static UInt n_supp_contexts = 0;
94
95
sewardjde4a1d02002-03-22 01:27:54 +000096/* forwards ... */
florian518850b2014-10-22 22:25:30 +000097static Supp* is_suppressible_error ( const Error* err );
sewardjde4a1d02002-03-22 01:27:54 +000098
sewardjb5f6f512005-03-10 23:59:00 +000099static ThreadId last_tid_printed = 1;
sewardjde4a1d02002-03-22 01:27:54 +0000100
sewardj8a7d4e42006-10-17 01:41:17 +0000101/* Stats: number of searches of the error list initiated. */
102static UWord em_errlist_searches = 0;
103
104/* Stats: number of comparisons done during error list
105 searching. */
106static UWord em_errlist_cmps = 0;
107
108/* Stats: number of searches of the suppression list initiated. */
109static UWord em_supplist_searches = 0;
110
111/* Stats: number of comparisons done during suppression list
112 searching. */
113static UWord em_supplist_cmps = 0;
114
sewardjde4a1d02002-03-22 01:27:54 +0000115/*------------------------------------------------------------*/
nethercote4a184902004-08-02 12:21:09 +0000116/*--- Error type ---*/
117/*------------------------------------------------------------*/
118
nethercote4a184902004-08-02 12:21:09 +0000119/* Errors. Extensible (via the 'extra' field). Tools can use a normal
njn02bc4b82005-05-15 17:28:26 +0000120 enum (with element values in the normal range (0..)) for 'ekind'.
nethercote4a184902004-08-02 12:21:09 +0000121 Functions for getting/setting the tool-relevant fields are in
njnc7561b92005-06-19 01:24:32 +0000122 include/pub_tool_errormgr.h.
nethercote4a184902004-08-02 12:21:09 +0000123
124 When errors are found and recorded with VG_(maybe_record_error)(), all
125 the tool must do is pass in the four parameters; core will
126 allocate/initialise the error record.
127*/
128struct _Error {
129 struct _Error* next;
sewardjdbada272005-07-02 21:16:30 +0000130 // Unique tag. This gives the error a unique identity (handle) by
131 // which it can be referred to afterwords. Currently only used for
132 // XML printing.
133 UInt unique;
nethercote4a184902004-08-02 12:21:09 +0000134 // NULL if unsuppressed; or ptr to suppression record.
135 Supp* supp;
136 Int count;
nethercote4a184902004-08-02 12:21:09 +0000137
138 // The tool-specific part
sewardjb8b79ad2008-03-03 01:35:41 +0000139 ThreadId tid; // Initialised by core
nethercote4a184902004-08-02 12:21:09 +0000140 ExeContext* where; // Initialised by core
njnd2b17112005-04-19 04:10:25 +0000141 ErrorKind ekind; // Used by ALL. Must be in the range (0..)
nethercote4a184902004-08-02 12:21:09 +0000142 Addr addr; // Used frequently
floriane543f302012-10-21 19:43:43 +0000143 const HChar* string; // Used frequently
nethercote4a184902004-08-02 12:21:09 +0000144 void* extra; // For any tool-specific extras
145};
146
sewardjb8b79ad2008-03-03 01:35:41 +0000147
florian8e3fbb52014-10-20 19:02:38 +0000148ExeContext* VG_(get_error_where) ( const Error* err )
nethercote4a184902004-08-02 12:21:09 +0000149{
150 return err->where;
151}
152
florian8e3fbb52014-10-20 19:02:38 +0000153ErrorKind VG_(get_error_kind) ( const Error* err )
nethercote4a184902004-08-02 12:21:09 +0000154{
155 return err->ekind;
156}
157
florian8e3fbb52014-10-20 19:02:38 +0000158Addr VG_(get_error_address) ( const Error* err )
nethercote4a184902004-08-02 12:21:09 +0000159{
160 return err->addr;
161}
162
florian8e3fbb52014-10-20 19:02:38 +0000163const HChar* VG_(get_error_string) ( const Error* err )
nethercote4a184902004-08-02 12:21:09 +0000164{
165 return err->string;
166}
167
florian8e3fbb52014-10-20 19:02:38 +0000168void* VG_(get_error_extra) ( const Error* err )
nethercote4a184902004-08-02 12:21:09 +0000169{
170 return err->extra;
171}
172
nethercotef2b11482004-08-02 12:36:01 +0000173UInt VG_(get_n_errs_found)( void )
174{
175 return n_errs_found;
176}
177
philippebaf69642012-02-15 22:29:30 +0000178UInt VG_(get_n_errs_shown)( void )
179{
180 return n_errs_shown;
181}
182
nethercote4a184902004-08-02 12:21:09 +0000183/*------------------------------------------------------------*/
184/*--- Suppression type ---*/
185/*------------------------------------------------------------*/
186
187/* Note: it is imperative this doesn't overlap with (0..) at all, as tools
188 * effectively extend it by defining their own enums in the (0..) range. */
189typedef
190 enum {
njna86f29e2006-12-14 02:55:58 +0000191 // Nb: thread errors are a relic of the time when Valgrind's core
192 // could detect them. This example is left commented-out as an
193 // example should new core errors ever be added.
194 ThreadSupp = -1, /* Matches ThreadErr */
nethercote4a184902004-08-02 12:21:09 +0000195 }
196 CoreSuppKind;
197
Elliott Hughesa0664b92017-04-18 17:46:52 -0700198/* Max number of callers for context in a suppression is
199 VG_DEEPEST_BACKTRACE. */
sewardjb5f6f512005-03-10 23:59:00 +0000200
nethercote4a184902004-08-02 12:21:09 +0000201/* For each caller specified for a suppression, record the nature of
202 the caller name. Not of interest to tools. */
203typedef
204 enum {
sewardjb5f6f512005-03-10 23:59:00 +0000205 NoName, /* Error case */
nethercote4a184902004-08-02 12:21:09 +0000206 ObjName, /* Name is of an shared object file. */
sewardj5e519302008-11-03 23:10:25 +0000207 FunName, /* Name is of a function. */
208 DotDotDot /* Frame-level wildcard */
nethercote4a184902004-08-02 12:21:09 +0000209 }
210 SuppLocTy;
211
sewardjb5f6f512005-03-10 23:59:00 +0000212typedef
213 struct {
214 SuppLocTy ty;
philippe2c5c05e2012-07-26 21:37:36 +0000215 Bool name_is_simple_str; /* True if name is a string without
216 '?' and '*' wildcard characters. */
florian19f91bb2012-11-10 22:29:54 +0000217 HChar* name; /* NULL for NoName and DotDotDot */
sewardjb5f6f512005-03-10 23:59:00 +0000218 }
219 SuppLoc;
220
nethercote4a184902004-08-02 12:21:09 +0000221/* Suppressions. Tools can get/set tool-relevant parts with functions
njnc7561b92005-06-19 01:24:32 +0000222 declared in include/pub_tool_errormgr.h. Extensible via the 'extra' field.
nethercote4a184902004-08-02 12:21:09 +0000223 Tools can use a normal enum (with element values in the normal range
njn02bc4b82005-05-15 17:28:26 +0000224 (0..)) for 'skind'. */
nethercote4a184902004-08-02 12:21:09 +0000225struct _Supp {
226 struct _Supp* next;
227 Int count; // The number of times this error has been suppressed.
florian19f91bb2012-11-10 22:29:54 +0000228 HChar* sname; // The name by which the suppression is referred to.
sewardjb5f6f512005-03-10 23:59:00 +0000229
philippe362441d2013-07-22 22:00:13 +0000230 // Index in VG_(clo_suppressions) giving filename from which suppression
231 // was read, and the lineno in this file where sname was read.
232 Int clo_suppressions_i;
233 Int sname_lineno;
234
sewardjb5f6f512005-03-10 23:59:00 +0000235 // Length of 'callers'
236 Int n_callers;
237 // Array of callers, for matching stack traces. First one (name of fn
238 // where err occurs) is mandatory; rest are optional.
239 SuppLoc* callers;
nethercote4a184902004-08-02 12:21:09 +0000240
241 /* The tool-specific part */
242 SuppKind skind; // What kind of suppression. Must use the range (0..).
florian19f91bb2012-11-10 22:29:54 +0000243 HChar* string; // String -- use is optional. NULL by default.
nethercote4a184902004-08-02 12:21:09 +0000244 void* extra; // Anything else -- use is optional. NULL by default.
245};
246
florian8e3fbb52014-10-20 19:02:38 +0000247SuppKind VG_(get_supp_kind) ( const Supp* su )
nethercote4a184902004-08-02 12:21:09 +0000248{
249 return su->skind;
250}
251
florian8e3fbb52014-10-20 19:02:38 +0000252HChar* VG_(get_supp_string) ( const Supp* su )
nethercote4a184902004-08-02 12:21:09 +0000253{
254 return su->string;
255}
256
florian8e3fbb52014-10-20 19:02:38 +0000257void* VG_(get_supp_extra) ( const Supp* su )
nethercote4a184902004-08-02 12:21:09 +0000258{
259 return su->extra;
260}
261
262
263void VG_(set_supp_kind) ( Supp* su, SuppKind skind )
264{
265 su->skind = skind;
266}
267
florian19f91bb2012-11-10 22:29:54 +0000268void VG_(set_supp_string) ( Supp* su, HChar* string )
nethercote4a184902004-08-02 12:21:09 +0000269{
270 su->string = string;
271}
272
273void VG_(set_supp_extra) ( Supp* su, void* extra )
274{
275 su->extra = extra;
276}
277
278
279/*------------------------------------------------------------*/
sewardjde4a1d02002-03-22 01:27:54 +0000280/*--- Helper fns ---*/
281/*------------------------------------------------------------*/
282
njn0087c502005-07-01 04:15:36 +0000283// Only show core errors if the tool wants to, we're not running with -q,
284// and were not outputting XML.
285Bool VG_(showing_core_errors)(void)
286{
287 return VG_(needs).core_errors && VG_(clo_verbosity) >= 1 && !VG_(clo_xml);
288}
289
sewardj738856f2009-07-15 14:48:32 +0000290/* Compare errors, to detect duplicates.
291*/
florian518850b2014-10-22 22:25:30 +0000292static Bool eq_Error ( VgRes res, const Error* e1, const Error* e2 )
sewardjde4a1d02002-03-22 01:27:54 +0000293{
njn810086f2002-11-14 12:42:47 +0000294 if (e1->ekind != e2->ekind)
sewardjde4a1d02002-03-22 01:27:54 +0000295 return False;
njn25e49d8e72002-09-23 09:36:25 +0000296 if (!VG_(eq_ExeContext)(res, e1->where, e2->where))
sewardjde4a1d02002-03-22 01:27:54 +0000297 return False;
298
njn810086f2002-11-14 12:42:47 +0000299 switch (e1->ekind) {
njna86f29e2006-12-14 02:55:58 +0000300 //(example code, see comment on CoreSuppKind above)
301 //case ThreadErr:
302 // vg_assert(VG_(needs).core_errors);
303 // return <something>
sewardjde4a1d02002-03-22 01:27:54 +0000304 default:
njn51d827b2005-05-09 01:02:08 +0000305 if (VG_(needs).tool_errors) {
306 return VG_TDICT_CALL(tool_eq_Error, res, e1, e2);
307 } else {
njn95ec8702004-11-22 16:46:13 +0000308 VG_(printf)("\nUnhandled error type: %u. VG_(needs).tool_errors\n"
njn25e49d8e72002-09-23 09:36:25 +0000309 "probably needs to be set.\n",
floriana5e06c32015-08-05 21:16:09 +0000310 (UInt)e1->ekind);
floriana4ca4fe2014-09-16 09:28:12 +0000311 VG_(core_panic)("unhandled error type");
njn25e49d8e72002-09-23 09:36:25 +0000312 }
sewardjde4a1d02002-03-22 01:27:54 +0000313 }
314}
315
sewardj738856f2009-07-15 14:48:32 +0000316
sewardj588adef2009-08-15 22:41:51 +0000317/* Helper functions for suppression generation: print a single line of
318 a suppression pseudo-stack-trace, either in XML or text mode. It's
319 important that the behaviour of these two functions exactly
320 corresponds.
sewardj738856f2009-07-15 14:48:32 +0000321*/
322#define ERRTXT_LEN 4096
323
sewardj588adef2009-08-15 22:41:51 +0000324static void printSuppForIp_XML(UInt n, Addr ip, void* uu_opaque)
sewardjde4a1d02002-03-22 01:27:54 +0000325{
florian46cc0452014-10-25 19:20:38 +0000326 const HChar *buf;
philippea0a73932014-06-15 15:42:20 +0000327 InlIPCursor* iipc = VG_(new_IIPC)(ip);
328 do {
florian46cc0452014-10-25 19:20:38 +0000329 if ( VG_(get_fnname_no_cxx_demangle) (ip, &buf, iipc) ) {
philippea0a73932014-06-15 15:42:20 +0000330 VG_(printf_xml)(" <sframe> <fun>%pS</fun> </sframe>\n", buf);
331 } else
florian46cc0452014-10-25 19:20:38 +0000332 if ( VG_(get_objname)(ip, &buf) ) {
philippea0a73932014-06-15 15:42:20 +0000333 VG_(printf_xml)(" <sframe> <obj>%pS</obj> </sframe>\n", buf);
334 } else {
335 VG_(printf_xml)(" <sframe> <obj>*</obj> </sframe>\n");
336 }
337 } while (VG_(next_IIPC)(iipc));
338 VG_(delete_IIPC)(iipc);
sewardjde4a1d02002-03-22 01:27:54 +0000339}
340
sewardj588adef2009-08-15 22:41:51 +0000341static void printSuppForIp_nonXML(UInt n, Addr ip, void* textV)
342{
florian46cc0452014-10-25 19:20:38 +0000343 const HChar *buf;
sewardj588adef2009-08-15 22:41:51 +0000344 XArray* /* of HChar */ text = (XArray*)textV;
philippea0a73932014-06-15 15:42:20 +0000345 InlIPCursor* iipc = VG_(new_IIPC)(ip);
346 do {
florian46cc0452014-10-25 19:20:38 +0000347 if ( VG_(get_fnname_no_cxx_demangle) (ip, &buf, iipc) ) {
philippea0a73932014-06-15 15:42:20 +0000348 VG_(xaprintf)(text, " fun:%s\n", buf);
349 } else
florian46cc0452014-10-25 19:20:38 +0000350 if ( VG_(get_objname)(ip, &buf) ) {
philippea0a73932014-06-15 15:42:20 +0000351 VG_(xaprintf)(text, " obj:%s\n", buf);
352 } else {
353 VG_(xaprintf)(text, " obj:*\n");
354 }
355 } while (VG_(next_IIPC)(iipc));
356 VG_(delete_IIPC)(iipc);
sewardj588adef2009-08-15 22:41:51 +0000357}
sewardj738856f2009-07-15 14:48:32 +0000358
359/* Generate a suppression for an error, either in text or XML mode.
360*/
florian518850b2014-10-22 22:25:30 +0000361static void gen_suppression(const Error* err)
sewardj738856f2009-07-15 14:48:32 +0000362{
floriandbb35842012-10-27 18:39:11 +0000363 const HChar* name;
sewardj588adef2009-08-15 22:41:51 +0000364 ExeContext* ec;
365 XArray* /* HChar */ text;
sewardj738856f2009-07-15 14:48:32 +0000366
sewardj588adef2009-08-15 22:41:51 +0000367 const HChar* dummy_name = "insert_a_suppression_name_here";
sewardj738856f2009-07-15 14:48:32 +0000368
sewardj588adef2009-08-15 22:41:51 +0000369 vg_assert(err);
370
sewardj588adef2009-08-15 22:41:51 +0000371 ec = VG_(get_error_where)(err);
372 vg_assert(ec);
373
374 name = VG_TDICT_CALL(tool_get_error_name, err);
375 if (NULL == name) {
376 VG_(umsg)("(%s does not allow error to be suppressed)\n",
377 VG_(details).name);
378 return;
sewardj738856f2009-07-15 14:48:32 +0000379 }
380
tom7420e0a2011-07-06 14:08:24 +0000381 /* In XML mode, we also need to print the plain text version of the
382 suppresion in a CDATA section. What that really means is, we
383 need to generate the plaintext version both in XML and text
384 mode. So generate it into TEXT. */
385 text = VG_(newXA)( VG_(malloc), "errormgr.gen_suppression.1",
386 VG_(free), sizeof(HChar) );
tom7420e0a2011-07-06 14:08:24 +0000387
sewardj588adef2009-08-15 22:41:51 +0000388 /* Ok. Generate the plain text version into TEXT. */
389 VG_(xaprintf)(text, "{\n");
390 VG_(xaprintf)(text, " <%s>\n", dummy_name);
391 VG_(xaprintf)(text, " %s:%s\n", VG_(details).name, name);
392
florian3e81b8b2014-10-07 14:28:52 +0000393 HChar *xtra = NULL;
394 SizeT xtra_size = 0;
395 SizeT num_written;
sewardj588adef2009-08-15 22:41:51 +0000396
florian3e81b8b2014-10-07 14:28:52 +0000397 do {
398 xtra_size += 256;
399 xtra = VG_(realloc)("errormgr.gen_suppression.2", xtra,xtra_size);
400 num_written = VG_TDICT_CALL(tool_get_extra_suppression_info,
401 err, xtra, xtra_size);
402 } while (num_written == xtra_size); // resize buffer and retry
403
404 // Ensure buffer is properly terminated
405 vg_assert(xtra[num_written] == '\0');
406
407 if (num_written)
sewardj588adef2009-08-15 22:41:51 +0000408 VG_(xaprintf)(text, " %s\n", xtra);
409
sewardj738856f2009-07-15 14:48:32 +0000410 // Print stack trace elements
sewardj2f340eb2011-01-28 00:44:52 +0000411 UInt n_ips = VG_(get_ExeContext_n_ips)(ec);
floriane2800c92014-09-15 20:57:45 +0000412 vg_assert(n_ips > 0);
Elliott Hughesa0664b92017-04-18 17:46:52 -0700413 vg_assert(n_ips <= VG_DEEPEST_BACKTRACE);
sewardj588adef2009-08-15 22:41:51 +0000414 VG_(apply_StackTrace)(printSuppForIp_nonXML,
415 text,
sewardj738856f2009-07-15 14:48:32 +0000416 VG_(get_ExeContext_StackTrace)(ec),
sewardj2f340eb2011-01-28 00:44:52 +0000417 n_ips);
sewardj738856f2009-07-15 14:48:32 +0000418
sewardj588adef2009-08-15 22:41:51 +0000419 VG_(xaprintf)(text, "}\n");
420 // zero terminate
421 VG_(xaprintf)(text, "%c", (HChar)0 );
422 // VG_(printf) of text
423
424 /* And now display it. */
425 if (! VG_(clo_xml) ) {
426
427 // the simple case
428 VG_(printf)("%s", (HChar*) VG_(indexXA)(text, 0) );
429
sewardj738856f2009-07-15 14:48:32 +0000430 } else {
sewardj588adef2009-08-15 22:41:51 +0000431
432 /* Now we have to print the XML directly. No need to go to the
433 effort of stuffing it in an XArray, since we won't need it
434 again. */
435 VG_(printf_xml)(" <suppression>\n");
436 VG_(printf_xml)(" <sname>%s</sname>\n", dummy_name);
bartb3af9cf2011-10-06 19:08:37 +0000437 VG_(printf_xml)(
438 " <skind>%pS:%pS</skind>\n", VG_(details).name, name);
florian3e81b8b2014-10-07 14:28:52 +0000439 if (num_written)
bartb3af9cf2011-10-06 19:08:37 +0000440 VG_(printf_xml)(" <skaux>%pS</skaux>\n", xtra);
sewardj588adef2009-08-15 22:41:51 +0000441
442 // Print stack trace elements
443 VG_(apply_StackTrace)(printSuppForIp_XML,
444 NULL,
445 VG_(get_ExeContext_StackTrace)(ec),
446 VG_(get_ExeContext_n_ips)(ec));
447
448 // And now the cdata bit
449 // XXX FIXME! properly handle the case where the raw text
450 // itself contains "]]>", as specified in Protocol 4.
451 VG_(printf_xml)(" <rawtext>\n");
452 VG_(printf_xml)("<![CDATA[\n");
sewardjde78f9a2009-08-15 23:33:04 +0000453 VG_(printf_xml)("%s", (HChar*) VG_(indexXA)(text, 0) );
sewardj588adef2009-08-15 22:41:51 +0000454 VG_(printf_xml)("]]>\n");
455 VG_(printf_xml)(" </rawtext>\n");
456 VG_(printf_xml)(" </suppression>\n");
457
sewardj738856f2009-07-15 14:48:32 +0000458 }
sewardj588adef2009-08-15 22:41:51 +0000459
460 VG_(deleteXA)(text);
florian3e81b8b2014-10-07 14:28:52 +0000461 VG_(free)(xtra);
sewardj738856f2009-07-15 14:48:32 +0000462}
463
464
465/* Figure out if we want to perform a given action for this error,
466 possibly by asking the user.
467*/
florian2b8059a2012-10-14 16:45:23 +0000468Bool VG_(is_action_requested) ( const HChar* action, Bool* clo )
sewardjde4a1d02002-03-22 01:27:54 +0000469{
florian19f91bb2012-11-10 22:29:54 +0000470 HChar ch, ch2;
sewardjde4a1d02002-03-22 01:27:54 +0000471 Int res;
472
sewardj738856f2009-07-15 14:48:32 +0000473 /* First off, we shouldn't be asking the user anything if
474 we're in XML mode. */
475 if (VG_(clo_xml))
476 return False; /* That's a Nein, oder Nay as they say down here in B-W */
477
njn43c799e2003-04-08 00:08:52 +0000478 if (*clo == False)
sewardjde4a1d02002-03-22 01:27:54 +0000479 return False;
480
sewardj738856f2009-07-15 14:48:32 +0000481 VG_(umsg)("\n");
sewardjde4a1d02002-03-22 01:27:54 +0000482
483 again:
484 VG_(printf)(
485 "==%d== "
njn43c799e2003-04-08 00:08:52 +0000486 "---- %s ? --- [Return/N/n/Y/y/C/c] ---- ",
487 VG_(getpid)(), action
sewardjde4a1d02002-03-22 01:27:54 +0000488 );
489
sewardj6024b212003-07-13 10:54:33 +0000490 res = VG_(read)(VG_(clo_input_fd), &ch, 1);
sewardjde4a1d02002-03-22 01:27:54 +0000491 if (res != 1) goto ioerror;
492 /* res == 1 */
493 if (ch == '\n') return False;
494 if (ch != 'N' && ch != 'n' && ch != 'Y' && ch != 'y'
495 && ch != 'C' && ch != 'c') goto again;
496
sewardj6024b212003-07-13 10:54:33 +0000497 res = VG_(read)(VG_(clo_input_fd), &ch2, 1);
sewardjde4a1d02002-03-22 01:27:54 +0000498 if (res != 1) goto ioerror;
499 if (ch2 != '\n') goto again;
500
njn43c799e2003-04-08 00:08:52 +0000501 /* No, don't want to do action. */
sewardjde4a1d02002-03-22 01:27:54 +0000502 if (ch == 'n' || ch == 'N') return False;
njn43c799e2003-04-08 00:08:52 +0000503 /* Yes, want to do action. */
sewardjde4a1d02002-03-22 01:27:54 +0000504 if (ch == 'y' || ch == 'Y') return True;
njn43c799e2003-04-08 00:08:52 +0000505 /* No, don't want to do action, and don't ask again either. */
sewardjde4a1d02002-03-22 01:27:54 +0000506 vg_assert(ch == 'c' || ch == 'C');
507
508 ioerror:
njn43c799e2003-04-08 00:08:52 +0000509 *clo = False;
sewardjde4a1d02002-03-22 01:27:54 +0000510 return False;
511}
512
513
sewardj738856f2009-07-15 14:48:32 +0000514/* Do text-mode actions on error, that is, immediately after an error
515 is printed. These are:
florianb9749a52015-07-24 11:50:12 +0000516 * possibly, call the GDB server
sewardj738856f2009-07-15 14:48:32 +0000517 * possibly, generate a suppression.
518 Note this should not be called in XML mode!
519*/
520static
florian518850b2014-10-22 22:25:30 +0000521void do_actions_on_error(const Error* err, Bool allow_db_attach)
sewardj738856f2009-07-15 14:48:32 +0000522{
523 Bool still_noisy = True;
524
sewardj3b290482011-05-06 21:02:55 +0000525 /* if user wants to debug from a certain error nr, then wait for gdb/vgdb */
526 if (VG_(clo_vgdb) != Vg_VgdbNo
527 && allow_db_attach
philippebaf69642012-02-15 22:29:30 +0000528 && VG_(dyn_vgdb_error) <= n_errs_shown) {
sewardj3b290482011-05-06 21:02:55 +0000529 VG_(umsg)("(action on error) vgdb me ... \n");
530 VG_(gdbserver)( err->tid );
531 VG_(umsg)("Continuing ...\n");
532 }
533
sewardj738856f2009-07-15 14:48:32 +0000534 /* Or maybe we want to generate the error's suppression? */
535 if (VG_(clo_gen_suppressions) == 2
536 || (VG_(clo_gen_suppressions) == 1
537 && VG_(is_action_requested)( "Print suppression", &still_noisy ))
538 ) {
539 gen_suppression(err);
540 }
541 if (VG_(clo_gen_suppressions) == 1 && !still_noisy)
542 VG_(clo_gen_suppressions) = 0;
543}
544
545
546/* Prints an error. Not entirely simple because of the differences
547 between XML and text mode output.
548
549 In XML mode:
550
551 * calls the tool's pre-show method, so the tool can create any
552 preamble ahead of the message, if it wants.
553
554 * prints the opening tag, and the <unique> and <tid> fields
555
556 * prints the tool-specific parts of the message
557
558 * if suppression generation is required, a suppression
559
560 * the closing tag
561
562 In text mode:
563
564 * calls the tool's pre-show method, so the tool can create any
565 preamble ahead of the message, if it wants.
566
567 * prints the tool-specific parts of the message
568
philipped4c37442015-03-21 16:13:08 +0000569 * calls do_actions_on_error. This optionally does a gdbserver call
570 and optionally prints a suppression; both of these may require user input.
sewardj738856f2009-07-15 14:48:32 +0000571*/
florian518850b2014-10-22 22:25:30 +0000572static void pp_Error ( const Error* err, Bool allow_db_attach, Bool xml )
sewardj738856f2009-07-15 14:48:32 +0000573{
574 /* If this fails, you probably specified your tool's method
575 dictionary incorrectly. */
576 vg_assert(VG_(needs).tool_errors);
577
sewardj3b290482011-05-06 21:02:55 +0000578 if (xml) {
sewardj738856f2009-07-15 14:48:32 +0000579
sewardj738856f2009-07-15 14:48:32 +0000580 /* Ensure that suppression generation is either completely
581 enabled or completely disabled; either way, we won't require
582 any user input. m_main.process_cmd_line_options should
583 ensure the asserted condition holds. */
584 vg_assert( VG_(clo_gen_suppressions) == 0 /* disabled */
585 || VG_(clo_gen_suppressions) == 2 /* for all errors */ );
586
587 /* Pre-show it to the tool */
588 VG_TDICT_CALL( tool_before_pp_Error, err );
589
590 /* standard preamble */
591 VG_(printf_xml)("<error>\n");
592 VG_(printf_xml)(" <unique>0x%x</unique>\n", err->unique);
floriana5e06c32015-08-05 21:16:09 +0000593 VG_(printf_xml)(" <tid>%u</tid>\n", err->tid);
florian49789512013-09-16 17:08:50 +0000594 ThreadState* tst = VG_(get_ThreadState)(err->tid);
595 if (tst->thread_name) {
596 VG_(printf_xml)(" <threadname>%s</threadname>\n", tst->thread_name);
597 }
sewardj738856f2009-07-15 14:48:32 +0000598
599 /* actually print it */
600 VG_TDICT_CALL( tool_pp_Error, err );
601
602 if (VG_(clo_gen_suppressions) > 0)
603 gen_suppression(err);
604
605 /* postamble */
606 VG_(printf_xml)("</error>\n");
njnb6267bd2009-08-12 00:14:16 +0000607 VG_(printf_xml)("\n");
sewardj738856f2009-07-15 14:48:32 +0000608
609 } else {
610
philippe7b3d3562014-11-12 19:43:29 +0000611 if (VG_(clo_error_markers)[0])
612 VG_(umsg)("%s\n", VG_(clo_error_markers)[0]);
sewardj738856f2009-07-15 14:48:32 +0000613 VG_TDICT_CALL( tool_before_pp_Error, err );
614
615 if (VG_(tdict).tool_show_ThreadIDs_for_errors
616 && err->tid > 0 && err->tid != last_tid_printed) {
florian49789512013-09-16 17:08:50 +0000617 ThreadState* tst = VG_(get_ThreadState)(err->tid);
618 if (tst->thread_name) {
floriana5e06c32015-08-05 21:16:09 +0000619 VG_(umsg)("Thread %u %s:\n", err->tid, tst->thread_name );
florian49789512013-09-16 17:08:50 +0000620 } else {
floriana5e06c32015-08-05 21:16:09 +0000621 VG_(umsg)("Thread %u:\n", err->tid );
florian49789512013-09-16 17:08:50 +0000622 }
sewardj738856f2009-07-15 14:48:32 +0000623 last_tid_printed = err->tid;
624 }
625
626 VG_TDICT_CALL( tool_pp_Error, err );
njnb6267bd2009-08-12 00:14:16 +0000627 VG_(umsg)("\n");
philippe7b3d3562014-11-12 19:43:29 +0000628 if (VG_(clo_error_markers)[1])
629 VG_(umsg)("%s\n", VG_(clo_error_markers)[1]);
sewardj738856f2009-07-15 14:48:32 +0000630
sewardj738856f2009-07-15 14:48:32 +0000631 }
philipped4c37442015-03-21 16:13:08 +0000632
633 do_actions_on_error(err, allow_db_attach);
sewardj738856f2009-07-15 14:48:32 +0000634}
635
636
sewardjb5f6f512005-03-10 23:59:00 +0000637/* Construct an error */
sewardj738856f2009-07-15 14:48:32 +0000638static
njn72718642003-07-24 08:45:32 +0000639void construct_error ( Error* err, ThreadId tid, ErrorKind ekind, Addr a,
floriane543f302012-10-21 19:43:43 +0000640 const HChar* s, void* extra, ExeContext* where )
sewardjde4a1d02002-03-22 01:27:54 +0000641{
sewardjdbada272005-07-02 21:16:30 +0000642 /* DO NOT MAKE unique_counter NON-STATIC */
643 static UInt unique_counter = 0;
644
floriane2800c92014-09-15 20:57:45 +0000645 vg_assert(tid < VG_N_THREADS);
njn72718642003-07-24 08:45:32 +0000646
njn810086f2002-11-14 12:42:47 +0000647 /* Core-only parts */
sewardjdbada272005-07-02 21:16:30 +0000648 err->unique = unique_counter++;
njn25e49d8e72002-09-23 09:36:25 +0000649 err->next = NULL;
650 err->supp = NULL;
651 err->count = 1;
njn72718642003-07-24 08:45:32 +0000652 err->tid = tid;
njn43c799e2003-04-08 00:08:52 +0000653 if (NULL == where)
sewardjadb102f2007-11-09 23:21:44 +0000654 err->where = VG_(record_ExeContext)( tid, 0 );
njn43c799e2003-04-08 00:08:52 +0000655 else
656 err->where = where;
njn1d6c4bc2002-11-21 13:38:08 +0000657
nethercote996901a2004-08-03 13:29:09 +0000658 /* Tool-relevant parts */
njn810086f2002-11-14 12:42:47 +0000659 err->ekind = ekind;
660 err->addr = a;
njn810086f2002-11-14 12:42:47 +0000661 err->extra = extra;
sewardja6022612003-07-24 23:50:17 +0000662 err->string = s;
663
njn25e49d8e72002-09-23 09:36:25 +0000664 /* sanity... */
njn72718642003-07-24 08:45:32 +0000665 vg_assert( tid < VG_N_THREADS );
njn25e49d8e72002-09-23 09:36:25 +0000666}
667
njn83f9e792005-06-11 05:04:09 +0000668
njn43c799e2003-04-08 00:08:52 +0000669
njn25e49d8e72002-09-23 09:36:25 +0000670/* Top-level entry point to the error management subsystem.
671 All detected errors are notified here; this routine decides if/when the
672 user should see the error. */
njn72718642003-07-24 08:45:32 +0000673void VG_(maybe_record_error) ( ThreadId tid,
philippec06f6842014-07-30 22:20:29 +0000674 ErrorKind ekind, Addr a,
675 const HChar* s, void* extra )
njn25e49d8e72002-09-23 09:36:25 +0000676{
njn810086f2002-11-14 12:42:47 +0000677 Error err;
678 Error* p;
679 Error* p_prev;
njn43c799e2003-04-08 00:08:52 +0000680 UInt extra_size;
njn695c16e2005-03-27 03:40:28 +0000681 VgRes exe_res = Vg_MedRes;
682 static Bool stopping_message = False;
683 static Bool slowdown_message = False;
sewardjde4a1d02002-03-22 01:27:54 +0000684
njn14319cc2005-03-13 06:26:22 +0000685 /* After M_COLLECT_NO_ERRORS_AFTER_SHOWN different errors have
686 been found, or M_COLLECT_NO_ERRORS_AFTER_FOUND total errors
sewardjf2537be2002-04-24 21:03:47 +0000687 have been found, just refuse to collect any more. This stops
688 the burden of the error-management system becoming excessive in
689 extremely buggy programs, although it does make it pretty
690 pointless to continue the Valgrind run after this point. */
sewardj2e432902002-06-13 20:44:00 +0000691 if (VG_(clo_error_limit)
njn695c16e2005-03-27 03:40:28 +0000692 && (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN
sewardj8a051722005-06-30 00:10:16 +0000693 || n_errs_found >= M_COLLECT_NO_ERRORS_AFTER_FOUND)
694 && !VG_(clo_xml)) {
sewardjde4a1d02002-03-22 01:27:54 +0000695 if (!stopping_message) {
sewardj738856f2009-07-15 14:48:32 +0000696 VG_(umsg)("\n");
sewardjf2537be2002-04-24 21:03:47 +0000697
njn695c16e2005-03-27 03:40:28 +0000698 if (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN) {
sewardj738856f2009-07-15 14:48:32 +0000699 VG_(umsg)(
sewardjf2537be2002-04-24 21:03:47 +0000700 "More than %d different errors detected. "
sewardj738856f2009-07-15 14:48:32 +0000701 "I'm not reporting any more.\n",
njn14319cc2005-03-13 06:26:22 +0000702 M_COLLECT_NO_ERRORS_AFTER_SHOWN );
sewardjf2537be2002-04-24 21:03:47 +0000703 } else {
sewardj738856f2009-07-15 14:48:32 +0000704 VG_(umsg)(
sewardjf2537be2002-04-24 21:03:47 +0000705 "More than %d total errors detected. "
sewardj738856f2009-07-15 14:48:32 +0000706 "I'm not reporting any more.\n",
njn14319cc2005-03-13 06:26:22 +0000707 M_COLLECT_NO_ERRORS_AFTER_FOUND );
sewardjf2537be2002-04-24 21:03:47 +0000708 }
709
sewardj738856f2009-07-15 14:48:32 +0000710 VG_(umsg)("Final error counts will be inaccurate. "
711 "Go fix your program!\n");
712 VG_(umsg)("Rerun with --error-limit=no to disable "
713 "this cutoff. Note\n");
714 VG_(umsg)("that errors may occur in your program without "
715 "prior warning from\n");
716 VG_(umsg)("Valgrind, because errors are no longer "
717 "being displayed.\n");
718 VG_(umsg)("\n");
sewardjde4a1d02002-03-22 01:27:54 +0000719 stopping_message = True;
720 }
721 return;
722 }
723
sewardjdc873c02011-07-24 16:02:33 +0000724 /* Ignore it if error acquisition is disabled for this thread. */
725 { ThreadState* tst = VG_(get_ThreadState)(tid);
726 if (tst->err_disablement_level > 0)
727 return;
728 }
729
njn14319cc2005-03-13 06:26:22 +0000730 /* After M_COLLECT_ERRORS_SLOWLY_AFTER different errors have
sewardjde4a1d02002-03-22 01:27:54 +0000731 been found, be much more conservative about collecting new
732 ones. */
sewardj8a051722005-06-30 00:10:16 +0000733 if (n_errs_shown >= M_COLLECT_ERRORS_SLOWLY_AFTER
734 && !VG_(clo_xml)) {
njn25e49d8e72002-09-23 09:36:25 +0000735 exe_res = Vg_LowRes;
sewardjde4a1d02002-03-22 01:27:54 +0000736 if (!slowdown_message) {
sewardj738856f2009-07-15 14:48:32 +0000737 VG_(umsg)("\n");
738 VG_(umsg)("More than %d errors detected. Subsequent errors\n",
739 M_COLLECT_ERRORS_SLOWLY_AFTER);
740 VG_(umsg)("will still be recorded, but in less "
741 "detail than before.\n");
sewardjde4a1d02002-03-22 01:27:54 +0000742 slowdown_message = True;
743 }
744 }
745
njn25e49d8e72002-09-23 09:36:25 +0000746 /* Build ourselves the error */
njn72718642003-07-24 08:45:32 +0000747 construct_error ( &err, tid, ekind, a, s, extra, NULL );
sewardjde4a1d02002-03-22 01:27:54 +0000748
749 /* First, see if we've got an error record matching this one. */
sewardj8a7d4e42006-10-17 01:41:17 +0000750 em_errlist_searches++;
751 p = errors;
752 p_prev = NULL;
sewardjde4a1d02002-03-22 01:27:54 +0000753 while (p != NULL) {
sewardj8a7d4e42006-10-17 01:41:17 +0000754 em_errlist_cmps++;
njn810086f2002-11-14 12:42:47 +0000755 if (eq_Error(exe_res, p, &err)) {
sewardjde4a1d02002-03-22 01:27:54 +0000756 /* Found it. */
757 p->count++;
758 if (p->supp != NULL) {
759 /* Deal correctly with suppressed errors. */
760 p->supp->count++;
nethercotef2b11482004-08-02 12:36:01 +0000761 n_errs_suppressed++;
sewardjde4a1d02002-03-22 01:27:54 +0000762 } else {
nethercotef2b11482004-08-02 12:36:01 +0000763 n_errs_found++;
sewardjde4a1d02002-03-22 01:27:54 +0000764 }
765
766 /* Move p to the front of the list so that future searches
sewardj3b290482011-05-06 21:02:55 +0000767 for it are faster. It also allows to print the last
768 error (see VG_(show_last_error). */
sewardjde4a1d02002-03-22 01:27:54 +0000769 if (p_prev != NULL) {
770 vg_assert(p_prev->next == p);
njn695c16e2005-03-27 03:40:28 +0000771 p_prev->next = p->next;
772 p->next = errors;
773 errors = p;
sewardjde4a1d02002-03-22 01:27:54 +0000774 }
sewardj7ebf7c32003-07-24 21:29:40 +0000775
sewardjde4a1d02002-03-22 01:27:54 +0000776 return;
777 }
778 p_prev = p;
779 p = p->next;
780 }
781
782 /* Didn't see it. Copy and add. */
783
njn43c799e2003-04-08 00:08:52 +0000784 /* OK, we're really going to collect it. The context is on the stack and
785 will disappear shortly, so we must copy it. First do the main
njn02bc4b82005-05-15 17:28:26 +0000786 (non-'extra') part.
njn25e49d8e72002-09-23 09:36:25 +0000787
njn02bc4b82005-05-15 17:28:26 +0000788 Then VG_(tdict).tool_update_extra can update the 'extra' part. This
njn51d827b2005-05-09 01:02:08 +0000789 is for when there are more details to fill in which take time to work
790 out but don't affect our earlier decision to include the error -- by
njn25e49d8e72002-09-23 09:36:25 +0000791 postponing those details until now, we avoid the extra work in the
njn810086f2002-11-14 12:42:47 +0000792 case where we ignore the error. Ugly.
njn43c799e2003-04-08 00:08:52 +0000793
njn02bc4b82005-05-15 17:28:26 +0000794 Then, if there is an 'extra' part, copy it too, using the size that
njn51d827b2005-05-09 01:02:08 +0000795 VG_(tdict).tool_update_extra returned. Also allow for people using
796 the void* extra field for a scalar value like an integer.
njn43c799e2003-04-08 00:08:52 +0000797 */
798
799 /* copy main part */
floriana2968cc2013-09-20 21:34:40 +0000800 p = VG_(malloc)("errormgr.mre.1", sizeof(Error));
njn25e49d8e72002-09-23 09:36:25 +0000801 *p = err;
njn43c799e2003-04-08 00:08:52 +0000802
njn02bc4b82005-05-15 17:28:26 +0000803 /* update 'extra' */
sewardjb5f6f512005-03-10 23:59:00 +0000804 switch (ekind) {
njna86f29e2006-12-14 02:55:58 +0000805 //(example code, see comment on CoreSuppKind above)
806 //case ThreadErr:
807 // vg_assert(VG_(needs).core_errors);
808 // extra_size = <something>
809 // break;
sewardjb5f6f512005-03-10 23:59:00 +0000810 default:
811 vg_assert(VG_(needs).tool_errors);
njn51d827b2005-05-09 01:02:08 +0000812 extra_size = VG_TDICT_CALL(tool_update_extra, p);
sewardjb5f6f512005-03-10 23:59:00 +0000813 break;
814 }
njn43c799e2003-04-08 00:08:52 +0000815
philippec06f6842014-07-30 22:20:29 +0000816 /* copy the error string, if there is one.
817 note: if we would have many errors with big strings, using a
818 DedupPoolAlloc for these strings will avoid duplicating
819 such string in each error using it. */
820 if (NULL != p->string) {
florian77eb20b2014-09-11 21:19:17 +0000821 p->string = VG_(strdup)("errormgr.mre.2", p->string);
philippec06f6842014-07-30 22:20:29 +0000822 }
823
njn02bc4b82005-05-15 17:28:26 +0000824 /* copy block pointed to by 'extra', if there is one */
sewardjb5f6f512005-03-10 23:59:00 +0000825 if (NULL != p->extra && 0 != extra_size) {
philippec06f6842014-07-30 22:20:29 +0000826 void* new_extra = VG_(malloc)("errormgr.mre.3", extra_size);
sewardjb5f6f512005-03-10 23:59:00 +0000827 VG_(memcpy)(new_extra, p->extra, extra_size);
828 p->extra = new_extra;
njn43c799e2003-04-08 00:08:52 +0000829 }
830
njn695c16e2005-03-27 03:40:28 +0000831 p->next = errors;
njn25e49d8e72002-09-23 09:36:25 +0000832 p->supp = is_suppressible_error(&err);
njn695c16e2005-03-27 03:40:28 +0000833 errors = p;
sewardjde4a1d02002-03-22 01:27:54 +0000834 if (p->supp == NULL) {
philippebaf69642012-02-15 22:29:30 +0000835 /* update stats */
njn606a4ae2009-08-11 00:52:40 +0000836 n_err_contexts++;
nethercotef2b11482004-08-02 12:36:01 +0000837 n_errs_found++;
philippebaf69642012-02-15 22:29:30 +0000838 n_errs_shown++;
sewardj738856f2009-07-15 14:48:32 +0000839 /* Actually show the error; more complex than you might think. */
sewardj3b290482011-05-06 21:02:55 +0000840 pp_Error( p, /*allow_db_attach*/True, VG_(clo_xml) );
sewardjde4a1d02002-03-22 01:27:54 +0000841 } else {
njn606a4ae2009-08-11 00:52:40 +0000842 n_supp_contexts++;
nethercotef2b11482004-08-02 12:36:01 +0000843 n_errs_suppressed++;
sewardjde4a1d02002-03-22 01:27:54 +0000844 p->supp->count++;
845 }
846}
847
njn43c799e2003-04-08 00:08:52 +0000848/* Second top-level entry point to the error management subsystem, for
nethercote7cc9c232004-01-21 15:08:04 +0000849 errors that the tool wants to report immediately, eg. because they're
njn43c799e2003-04-08 00:08:52 +0000850 guaranteed to only happen once. This avoids all the recording and
851 comparing stuff. But they can be suppressed; returns True if it is
njn02bc4b82005-05-15 17:28:26 +0000852 suppressed. Bool 'print_error' dictates whether to print the error.
njn18afe5d2009-08-10 08:25:39 +0000853 Bool 'count_error' dictates whether to count the error in n_errs_found.
njn47363ab2003-04-21 13:24:40 +0000854*/
floriane543f302012-10-21 19:43:43 +0000855Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind, Addr a, const HChar* s,
njn3e884182003-04-15 13:03:23 +0000856 void* extra, ExeContext* where, Bool print_error,
njn18afe5d2009-08-10 08:25:39 +0000857 Bool allow_db_attach, Bool count_error )
njn43c799e2003-04-08 00:08:52 +0000858{
njnfb289bc2007-01-12 23:59:50 +0000859 Error err;
860 Supp *su;
njn43c799e2003-04-08 00:08:52 +0000861
sewardjdc873c02011-07-24 16:02:33 +0000862 /* Ignore it if error acquisition is disabled for this thread. */
863 ThreadState* tst = VG_(get_ThreadState)(tid);
864 if (tst->err_disablement_level > 0)
865 return False; /* ignored, not suppressed */
866
njn43c799e2003-04-08 00:08:52 +0000867 /* Build ourselves the error */
njn72718642003-07-24 08:45:32 +0000868 construct_error ( &err, tid, ekind, a, s, extra, where );
njn43c799e2003-04-08 00:08:52 +0000869
870 /* Unless it's suppressed, we're going to show it. Don't need to make
871 a copy, because it's only temporary anyway.
872
njn02bc4b82005-05-15 17:28:26 +0000873 Then update the 'extra' part with VG_(tdict).tool_update_extra),
njn51d827b2005-05-09 01:02:08 +0000874 because that can have an affect on whether it's suppressed. Ignore
875 the size return value of VG_(tdict).tool_update_extra, because we're
philippec06f6842014-07-30 22:20:29 +0000876 not copying 'extra'. Similarly, 's' is also not copied. */
njn51d827b2005-05-09 01:02:08 +0000877 (void)VG_TDICT_CALL(tool_update_extra, &err);
njn43c799e2003-04-08 00:08:52 +0000878
njnfb289bc2007-01-12 23:59:50 +0000879 su = is_suppressible_error(&err);
880 if (NULL == su) {
njn606a4ae2009-08-11 00:52:40 +0000881 if (count_error) {
njn18afe5d2009-08-10 08:25:39 +0000882 n_errs_found++;
njn606a4ae2009-08-11 00:52:40 +0000883 n_err_contexts++;
884 }
njn43c799e2003-04-08 00:08:52 +0000885
886 if (print_error) {
sewardj738856f2009-07-15 14:48:32 +0000887 /* update stats */
njnfb289bc2007-01-12 23:59:50 +0000888 n_errs_shown++;
philippebaf69642012-02-15 22:29:30 +0000889 /* Actually show the error; more complex than you might think. */
890 pp_Error(&err, allow_db_attach, VG_(clo_xml));
njn43c799e2003-04-08 00:08:52 +0000891 }
njn43c799e2003-04-08 00:08:52 +0000892 return False;
893
894 } else {
njn663ab792009-08-13 04:24:38 +0000895 if (count_error) {
896 n_errs_suppressed++;
897 n_supp_contexts++;
898 }
njnfb289bc2007-01-12 23:59:50 +0000899 su->count++;
njn43c799e2003-04-08 00:08:52 +0000900 return True;
901 }
902}
903
sewardjde4a1d02002-03-22 01:27:54 +0000904
sewardjde4a1d02002-03-22 01:27:54 +0000905/*------------------------------------------------------------*/
906/*--- Exported fns ---*/
907/*------------------------------------------------------------*/
908
sewardj71bc3cb2005-05-19 00:25:45 +0000909/* Show the used suppressions. Returns False if no suppression
910 got used. */
911static Bool show_used_suppressions ( void )
912{
913 Supp *su;
914 Bool any_supp;
915
sewardj7c9e57c2005-05-24 14:21:45 +0000916 if (VG_(clo_xml))
sewardj738856f2009-07-15 14:48:32 +0000917 VG_(printf_xml)("<suppcounts>\n");
sewardj7c9e57c2005-05-24 14:21:45 +0000918
sewardj71bc3cb2005-05-19 00:25:45 +0000919 any_supp = False;
920 for (su = suppressions; su != NULL; su = su->next) {
921 if (su->count <= 0)
922 continue;
sewardj71bc3cb2005-05-19 00:25:45 +0000923 if (VG_(clo_xml)) {
bartb3af9cf2011-10-06 19:08:37 +0000924 VG_(printf_xml)( " <pair>\n"
sewardj738856f2009-07-15 14:48:32 +0000925 " <count>%d</count>\n"
bartb3af9cf2011-10-06 19:08:37 +0000926 " <name>%pS</name>\n"
sewardj738856f2009-07-15 14:48:32 +0000927 " </pair>\n",
928 su->count, su->sname );
sewardj71bc3cb2005-05-19 00:25:45 +0000929 } else {
florian3e81b8b2014-10-07 14:28:52 +0000930 HChar *xtra = NULL;
931 Int xtra_size = 0;
932 SizeT num_written;
sewardj2d9e8742009-08-07 15:46:56 +0000933 // blank line before the first shown suppression, if any
934 if (!any_supp)
935 VG_(dmsg)("\n");
florian3e81b8b2014-10-07 14:28:52 +0000936
937 do {
938 xtra_size += 256;
939 xtra = VG_(realloc)("errormgr.sus.1", xtra, xtra_size);
940 num_written = VG_TDICT_CALL(tool_print_extra_suppression_use,
941 su, xtra, xtra_size);
942 } while (num_written == xtra_size); // resize buffer and retry
943
944 // Ensure buffer is properly terminated
945 vg_assert(xtra[num_written] == '\0');
946
florian79316272014-10-07 18:36:28 +0000947 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
948 su->clo_suppressions_i);
philippe4e32d672013-10-17 22:10:41 +0000949 VG_(dmsg)("used_suppression: %6d %s %s:%d%s%s\n", su->count, su->sname,
florian79316272014-10-07 18:36:28 +0000950 filename,
philippe4e32d672013-10-17 22:10:41 +0000951 su->sname_lineno,
florian3e81b8b2014-10-07 14:28:52 +0000952 num_written ? " " : "", xtra);
953 VG_(free)(xtra);
sewardj71bc3cb2005-05-19 00:25:45 +0000954 }
sewardj2d9e8742009-08-07 15:46:56 +0000955 any_supp = True;
sewardj71bc3cb2005-05-19 00:25:45 +0000956 }
957
sewardj7c9e57c2005-05-24 14:21:45 +0000958 if (VG_(clo_xml))
sewardj738856f2009-07-15 14:48:32 +0000959 VG_(printf_xml)("</suppcounts>\n");
sewardj7c9e57c2005-05-24 14:21:45 +0000960
sewardj71bc3cb2005-05-19 00:25:45 +0000961 return any_supp;
962}
963
sewardj9f297ca2005-05-20 02:29:52 +0000964/* Show all the errors that occurred, and possibly also the
965 suppressions used. */
sewardj3b290482011-05-06 21:02:55 +0000966void VG_(show_all_errors) ( Int verbosity, Bool xml )
sewardjde4a1d02002-03-22 01:27:54 +0000967{
njn810086f2002-11-14 12:42:47 +0000968 Int i, n_min;
njn810086f2002-11-14 12:42:47 +0000969 Error *p, *p_min;
njn810086f2002-11-14 12:42:47 +0000970 Bool any_supp;
sewardjde4a1d02002-03-22 01:27:54 +0000971
sewardj3b290482011-05-06 21:02:55 +0000972 if (verbosity == 0)
sewardjde4a1d02002-03-22 01:27:54 +0000973 return;
974
njn606a4ae2009-08-11 00:52:40 +0000975 /* If we're printing XML, just show the suppressions and stop. */
sewardj3b290482011-05-06 21:02:55 +0000976 if (xml) {
sewardj71bc3cb2005-05-19 00:25:45 +0000977 (void)show_used_suppressions();
978 return;
979 }
980
981 /* We only get here if not printing XML. */
sewardj738856f2009-07-15 14:48:32 +0000982 VG_(umsg)("ERROR SUMMARY: "
floriana5e06c32015-08-05 21:16:09 +0000983 "%u errors from %u contexts (suppressed: %u from %u)\n",
sewardj738856f2009-07-15 14:48:32 +0000984 n_errs_found, n_err_contexts,
985 n_errs_suppressed, n_supp_contexts );
sewardjde4a1d02002-03-22 01:27:54 +0000986
sewardj3b290482011-05-06 21:02:55 +0000987 if (verbosity <= 1)
sewardjde4a1d02002-03-22 01:27:54 +0000988 return;
989
sewardj2d9e8742009-08-07 15:46:56 +0000990 // We do the following only at -v or above, and only in non-XML
991 // mode
992
sewardj3b290482011-05-06 21:02:55 +0000993 /* Print the contexts in order of increasing error count.
994 Once an error is shown, we add a huge value to its count to filter it
philippe362441d2013-07-22 22:00:13 +0000995 out.
996 After having shown all errors, we reset count to the original value. */
sewardjde4a1d02002-03-22 01:27:54 +0000997 for (i = 0; i < n_err_contexts; i++) {
998 n_min = (1 << 30) - 1;
999 p_min = NULL;
njn695c16e2005-03-27 03:40:28 +00001000 for (p = errors; p != NULL; p = p->next) {
sewardjde4a1d02002-03-22 01:27:54 +00001001 if (p->supp != NULL) continue;
1002 if (p->count < n_min) {
1003 n_min = p->count;
1004 p_min = p;
1005 }
1006 }
njn663ab792009-08-13 04:24:38 +00001007 // XXX: this isn't right. See bug 203651.
floriana4ca4fe2014-09-16 09:28:12 +00001008 if (p_min == NULL) continue; //VG_(core_panic)("show_all_errors()");
sewardjde4a1d02002-03-22 01:27:54 +00001009
sewardj738856f2009-07-15 14:48:32 +00001010 VG_(umsg)("\n");
floriana5e06c32015-08-05 21:16:09 +00001011 VG_(umsg)("%d errors in context %d of %u:\n",
sewardj738856f2009-07-15 14:48:32 +00001012 p_min->count, i+1, n_err_contexts);
sewardj3b290482011-05-06 21:02:55 +00001013 pp_Error( p_min, False/*allow_db_attach*/, False /* xml */ );
sewardj738856f2009-07-15 14:48:32 +00001014
1015 // We're not printing XML -- we'd have exited above if so.
sewardj3b290482011-05-06 21:02:55 +00001016 vg_assert(! xml);
sewardjde4a1d02002-03-22 01:27:54 +00001017
1018 if ((i+1 == VG_(clo_dump_error))) {
sewardj7cf4e6b2008-05-01 20:24:26 +00001019 StackTrace ips = VG_(get_ExeContext_StackTrace)(p_min->where);
sewardjfa8ec112005-01-19 11:55:34 +00001020 VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to debugging*/,
njn394213a2005-06-19 18:38:24 +00001021 ips[0], /*debugging*/True, 0xFE/*verbosity*/,
sewardj0ec07f32006-01-12 12:32:32 +00001022 /*bbs_done*/0,
1023 /*allow redir?*/True);
sewardjde4a1d02002-03-22 01:27:54 +00001024 }
1025
sewardj3b290482011-05-06 21:02:55 +00001026 p_min->count = p_min->count + (1 << 30);
sewardjde4a1d02002-03-22 01:27:54 +00001027 }
1028
sewardj3b290482011-05-06 21:02:55 +00001029 /* reset the counts, otherwise a 2nd call does not show anything anymore */
1030 for (p = errors; p != NULL; p = p->next) {
1031 if (p->count >= (1 << 30))
1032 p->count = p->count - (1 << 30);
1033 }
1034
1035
sewardj71bc3cb2005-05-19 00:25:45 +00001036 any_supp = show_used_suppressions();
sewardjde4a1d02002-03-22 01:27:54 +00001037
sewardj2d9e8742009-08-07 15:46:56 +00001038 if (any_supp)
sewardj738856f2009-07-15 14:48:32 +00001039 VG_(umsg)("\n");
sewardj2d9e8742009-08-07 15:46:56 +00001040 // reprint this, so users don't have to scroll way up to find
1041 // the first printing
1042 VG_(umsg)("ERROR SUMMARY: "
floriana5e06c32015-08-05 21:16:09 +00001043 "%u errors from %u contexts (suppressed: %u from %u)\n",
sewardj2d9e8742009-08-07 15:46:56 +00001044 n_errs_found, n_err_contexts, n_errs_suppressed,
1045 n_supp_contexts );
sewardjde4a1d02002-03-22 01:27:54 +00001046}
1047
sewardj3b290482011-05-06 21:02:55 +00001048void VG_(show_last_error) ( void )
1049{
1050 if (n_err_contexts == 0) {
1051 VG_(umsg)("No errors yet\n");
1052 return;
1053 }
1054
1055 pp_Error( errors, False/*allow_db_attach*/, False/*xml*/ );
1056}
1057
sewardj9f297ca2005-05-20 02:29:52 +00001058
1059/* Show occurrence counts of all errors, in XML form. */
1060void VG_(show_error_counts_as_XML) ( void )
1061{
1062 Error* err;
sewardj738856f2009-07-15 14:48:32 +00001063 VG_(printf_xml)("<errorcounts>\n");
sewardj9f297ca2005-05-20 02:29:52 +00001064 for (err = errors; err != NULL; err = err->next) {
1065 if (err->supp != NULL)
1066 continue;
1067 if (err->count <= 0)
1068 continue;
sewardj738856f2009-07-15 14:48:32 +00001069 VG_(printf_xml)(" <pair>\n");
1070 VG_(printf_xml)(" <count>%d</count>\n", err->count);
1071 VG_(printf_xml)(" <unique>0x%x</unique>\n", err->unique);
1072 VG_(printf_xml)(" </pair>\n");
sewardj9f297ca2005-05-20 02:29:52 +00001073 }
sewardj738856f2009-07-15 14:48:32 +00001074 VG_(printf_xml)("</errorcounts>\n");
njnb6267bd2009-08-12 00:14:16 +00001075 VG_(printf_xml)("\n");
sewardj9f297ca2005-05-20 02:29:52 +00001076}
1077
1078
sewardjde4a1d02002-03-22 01:27:54 +00001079/*------------------------------------------------------------*/
sewardjd7a02db2008-12-12 08:07:49 +00001080/*--- Suppression parsing ---*/
sewardjde4a1d02002-03-22 01:27:54 +00001081/*------------------------------------------------------------*/
1082
sewardj8a7d4e42006-10-17 01:41:17 +00001083/* Get the next char from fd into *out_buf. Returns 1 if success,
1084 0 if eof or < 0 if error. */
1085
florian19f91bb2012-11-10 22:29:54 +00001086static Int get_char ( Int fd, HChar* out_buf )
sewardj8a7d4e42006-10-17 01:41:17 +00001087{
1088 Int r;
florian19f91bb2012-11-10 22:29:54 +00001089 static HChar buf[256];
sewardj8a7d4e42006-10-17 01:41:17 +00001090 static Int buf_size = 0;
1091 static Int buf_used = 0;
florian3130eab2014-11-14 19:25:08 +00001092 vg_assert(buf_size >= 0 && buf_size <= sizeof buf);
sewardj8a7d4e42006-10-17 01:41:17 +00001093 vg_assert(buf_used >= 0 && buf_used <= buf_size);
1094 if (buf_used == buf_size) {
florian3130eab2014-11-14 19:25:08 +00001095 r = VG_(read)(fd, buf, sizeof buf);
sewardj8a7d4e42006-10-17 01:41:17 +00001096 if (r < 0) return r; /* read failed */
florian3130eab2014-11-14 19:25:08 +00001097 vg_assert(r >= 0 && r <= sizeof buf);
sewardj8a7d4e42006-10-17 01:41:17 +00001098 buf_size = r;
1099 buf_used = 0;
1100 }
1101 if (buf_size == 0)
1102 return 0; /* eof */
florian3130eab2014-11-14 19:25:08 +00001103 vg_assert(buf_size >= 0 && buf_size <= sizeof buf);
sewardj8a7d4e42006-10-17 01:41:17 +00001104 vg_assert(buf_used >= 0 && buf_used < buf_size);
1105 *out_buf = buf[buf_used];
1106 buf_used++;
1107 return 1;
1108}
1109
philippe2193a7c2012-12-08 17:54:16 +00001110// Get a non blank non comment line.
1111// Returns True if eof.
1112static Bool get_nbnc_line ( Int fd, HChar** bufpp, SizeT* nBufp, Int* lineno )
sewardjde4a1d02002-03-22 01:27:54 +00001113{
florian19f91bb2012-11-10 22:29:54 +00001114 HChar* buf = *bufpp;
njn35db56c2009-07-24 07:38:29 +00001115 SizeT nBuf = *nBufp;
florian19f91bb2012-11-10 22:29:54 +00001116 HChar ch;
njn35db56c2009-07-24 07:38:29 +00001117 Int n, i;
philippe362441d2013-07-22 22:00:13 +00001118
1119 vg_assert(lineno); // lineno needed to correctly track line numbers.
1120
sewardjde4a1d02002-03-22 01:27:54 +00001121 while (True) {
philippe2193a7c2012-12-08 17:54:16 +00001122 buf[0] = 0;
sewardjde4a1d02002-03-22 01:27:54 +00001123 /* First, read until a non-blank char appears. */
1124 while (True) {
sewardj8a7d4e42006-10-17 01:41:17 +00001125 n = get_char(fd, &ch);
njn0c0f32a2005-03-26 04:14:01 +00001126 if (n == 1 && !VG_(isspace)(ch)) break;
florian190bd522014-09-01 21:03:54 +00001127 if (n == 1 && ch == '\n')
bart050eec52009-07-27 12:03:03 +00001128 (*lineno)++;
sewardj8a7d4e42006-10-17 01:41:17 +00001129 if (n <= 0) return True;
sewardjde4a1d02002-03-22 01:27:54 +00001130 }
1131
1132 /* Now, read the line into buf. */
1133 i = 0;
1134 buf[i++] = ch; buf[i] = 0;
1135 while (True) {
sewardj8a7d4e42006-10-17 01:41:17 +00001136 n = get_char(fd, &ch);
1137 if (n <= 0) return False; /* the next call will return True */
florian190bd522014-09-01 21:03:54 +00001138 if (ch == '\n')
bart050eec52009-07-27 12:03:03 +00001139 (*lineno)++;
sewardjde4a1d02002-03-22 01:27:54 +00001140 if (ch == '\n') break;
njn35db56c2009-07-24 07:38:29 +00001141 if (i > 0 && i == nBuf-1) {
1142 *nBufp = nBuf = nBuf * 2;
1143 #define RIDICULOUS 100000
1144 vg_assert2(nBuf < RIDICULOUS, // Just a sanity check, really.
1145 "VG_(get_line): line longer than %d chars, aborting\n",
1146 RIDICULOUS);
1147 *bufpp = buf = VG_(realloc)("errormgr.get_line.1", buf, nBuf);
1148 }
sewardjde4a1d02002-03-22 01:27:54 +00001149 buf[i++] = ch; buf[i] = 0;
1150 }
njn0c0f32a2005-03-26 04:14:01 +00001151 while (i > 1 && VG_(isspace)(buf[i-1])) {
sewardjde4a1d02002-03-22 01:27:54 +00001152 i--; buf[i] = 0;
1153 };
1154
philippe362441d2013-07-22 22:00:13 +00001155 // VG_(printf)("The line *%p %d is '%s'\n", lineno, *lineno, buf);
sewardjde4a1d02002-03-22 01:27:54 +00001156 /* Ok, we have a line. If a non-comment line, return.
1157 If a comment line, start all over again. */
1158 if (buf[0] != '#') return False;
1159 }
1160}
1161
philippe2193a7c2012-12-08 17:54:16 +00001162// True if buf starts with fun: or obj: or is ...
florian518850b2014-10-22 22:25:30 +00001163static Bool is_location_line (const HChar* buf)
philippe2193a7c2012-12-08 17:54:16 +00001164{
1165 return VG_(strncmp)(buf, "fun:", 4) == 0
1166 || VG_(strncmp)(buf, "obj:", 4) == 0
1167 || VG_(strcmp)(buf, "...") == 0;
1168}
1169
1170Bool VG_(get_line) ( Int fd, HChar** bufpp, SizeT* nBufp, Int* lineno )
1171{
1172 Bool eof = get_nbnc_line (fd, bufpp, nBufp, lineno);
1173
1174 if (eof)
1175 return True;
1176
1177 if (is_location_line(*bufpp))
1178 return True; // Not a extra suppr line
1179 else
philippe362441d2013-07-22 22:00:13 +00001180 return False; // A suppression extra line
philippe2193a7c2012-12-08 17:54:16 +00001181}
sewardjde4a1d02002-03-22 01:27:54 +00001182
philippe2c5c05e2012-07-26 21:37:36 +00001183/* True if s contains no wildcard (?, *) characters. */
florian19f91bb2012-11-10 22:29:54 +00001184static Bool is_simple_str (const HChar *s)
philippe2c5c05e2012-07-26 21:37:36 +00001185{
philippe2c5c05e2012-07-26 21:37:36 +00001186 while (*s) {
1187 if (*s == '?' || *s == '*')
1188 return False;
1189 s++;
1190 }
1191 return True;
1192}
1193
philippe7d69fd92012-02-26 21:26:00 +00001194/* buf contains the raw name of a caller, supposedly either
sewardjde4a1d02002-03-22 01:27:54 +00001195 fun:some_function_name or
philippe7d69fd92012-02-26 21:26:00 +00001196 obj:some_object_name or
1197 ...
1198 Set p->ty and p->name accordingly.
1199 p->name is allocated and set to the string
1200 after the descriptor (fun: or obj:) part.
sewardjde4a1d02002-03-22 01:27:54 +00001201 Returns False if failed.
1202*/
florian518850b2014-10-22 22:25:30 +00001203static Bool setLocationTy ( SuppLoc* p, const HChar *buf )
sewardjde4a1d02002-03-22 01:27:54 +00001204{
philippe7d69fd92012-02-26 21:26:00 +00001205 if (VG_(strncmp)(buf, "fun:", 4) == 0) {
florian77eb20b2014-09-11 21:19:17 +00001206 p->name = VG_(strdup)("errormgr.sLTy.1", buf+4);
philippe2c5c05e2012-07-26 21:37:36 +00001207 p->name_is_simple_str = is_simple_str (p->name);
sewardjb5f6f512005-03-10 23:59:00 +00001208 p->ty = FunName;
sewardjde4a1d02002-03-22 01:27:54 +00001209 return True;
1210 }
philippe7d69fd92012-02-26 21:26:00 +00001211 if (VG_(strncmp)(buf, "obj:", 4) == 0) {
florian77eb20b2014-09-11 21:19:17 +00001212 p->name = VG_(strdup)("errormgr.sLTy.2", buf+4);
philippe2c5c05e2012-07-26 21:37:36 +00001213 p->name_is_simple_str = is_simple_str (p->name);
sewardjb5f6f512005-03-10 23:59:00 +00001214 p->ty = ObjName;
sewardjde4a1d02002-03-22 01:27:54 +00001215 return True;
1216 }
philippe7d69fd92012-02-26 21:26:00 +00001217 if (VG_(strcmp)(buf, "...") == 0) {
sewardj5e519302008-11-03 23:10:25 +00001218 p->name = NULL;
philippe2c5c05e2012-07-26 21:37:36 +00001219 p->name_is_simple_str = False;
sewardj5e519302008-11-03 23:10:25 +00001220 p->ty = DotDotDot;
1221 return True;
1222 }
1223 VG_(printf)("location should be \"...\", or should start "
1224 "with \"fun:\" or \"obj:\"\n");
sewardjde4a1d02002-03-22 01:27:54 +00001225 return False;
1226}
1227
1228
nethercote7cc9c232004-01-21 15:08:04 +00001229/* Look for "tool" in a string like "tool1,tool2,tool3" */
florian518850b2014-10-22 22:25:30 +00001230static Bool tool_name_present(const HChar *name, const HChar *names)
njn11cc9252002-10-07 14:42:59 +00001231{
1232 Bool found;
florian19f91bb2012-11-10 22:29:54 +00001233 HChar *s = NULL; /* Shut gcc up */
njn11cc9252002-10-07 14:42:59 +00001234 Int len = VG_(strlen)(name);
1235
1236 found = (NULL != (s = VG_(strstr)(names, name)) &&
1237 (s == names || *(s-1) == ',') &&
1238 (*(s+len) == ',' || *(s+len) == '\0')
1239 );
1240
1241 return found;
1242}
1243
philippe362441d2013-07-22 22:00:13 +00001244/* Read suppressions from the file specified in
1245 VG_(clo_suppressions)[clo_suppressions_i]
sewardjde4a1d02002-03-22 01:27:54 +00001246 and place them in the suppressions list. If there's any difficulty
1247 doing this, just give up -- there's no point in trying to recover.
1248*/
philippe362441d2013-07-22 22:00:13 +00001249static void load_one_suppressions_file ( Int clo_suppressions_i )
sewardjde4a1d02002-03-22 01:27:54 +00001250{
florian79316272014-10-07 18:36:28 +00001251 const HChar* filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1252 clo_suppressions_i);
sewardj92645592005-07-23 09:18:34 +00001253 SysRes sres;
sewardj5e519302008-11-03 23:10:25 +00001254 Int fd, i, j, lineno = 0;
philippe2193a7c2012-12-08 17:54:16 +00001255 Bool got_a_location_line_read_by_tool;
sewardj92645592005-07-23 09:18:34 +00001256 Bool eof;
njn35db56c2009-07-24 07:38:29 +00001257 SizeT nBuf = 200;
florian19f91bb2012-11-10 22:29:54 +00001258 HChar* buf = VG_(malloc)("errormgr.losf.1", nBuf);
1259 HChar* tool_names;
1260 HChar* supp_name;
florian2b8059a2012-10-14 16:45:23 +00001261 const HChar* err_str = NULL;
Elliott Hughesa0664b92017-04-18 17:46:52 -07001262 SuppLoc tmp_callers[VG_DEEPEST_BACKTRACE];
njnc40c3a82002-10-02 11:02:27 +00001263
njncc37d2e2009-06-24 03:49:19 +00001264 // Check it's not a directory.
1265 if (VG_(is_dir)( filename )) {
1266 if (VG_(clo_xml))
sewardj09361bf2011-01-28 00:19:25 +00001267 VG_(printf_xml)("</valgrindoutput>\n");
sewardj738856f2009-07-15 14:48:32 +00001268 VG_(umsg)("FATAL: suppressions file \"%s\" is a directory\n", filename );
njncc37d2e2009-06-24 03:49:19 +00001269 VG_(exit)(1);
1270 }
1271
1272 // Open the suppression file.
sewardj92645592005-07-23 09:18:34 +00001273 sres = VG_(open)( filename, VKI_O_RDONLY, 0 );
njncda2f0f2009-05-18 02:12:08 +00001274 if (sr_isError(sres)) {
sewardjf349d552005-11-14 17:01:01 +00001275 if (VG_(clo_xml))
sewardj09361bf2011-01-28 00:19:25 +00001276 VG_(printf_xml)("</valgrindoutput>\n");
sewardj738856f2009-07-15 14:48:32 +00001277 VG_(umsg)("FATAL: can't open suppressions file \"%s\"\n", filename );
sewardjde4a1d02002-03-22 01:27:54 +00001278 VG_(exit)(1);
1279 }
njncda2f0f2009-05-18 02:12:08 +00001280 fd = sr_Res(sres);
sewardjde4a1d02002-03-22 01:27:54 +00001281
sewardj92645592005-07-23 09:18:34 +00001282# define BOMB(S) { err_str = S; goto syntax_error; }
sewardjb5f6f512005-03-10 23:59:00 +00001283
sewardjde4a1d02002-03-22 01:27:54 +00001284 while (True) {
nethercote7cc9c232004-01-21 15:08:04 +00001285 /* Assign and initialise the two suppression halves (core and tool) */
njn810086f2002-11-14 12:42:47 +00001286 Supp* supp;
florian77eb20b2014-09-11 21:19:17 +00001287 supp = VG_(malloc)("errormgr.losf.1", sizeof(Supp));
sewardjde4a1d02002-03-22 01:27:54 +00001288 supp->count = 0;
sewardjb5f6f512005-03-10 23:59:00 +00001289
1290 // Initialise temporary reading-in buffer.
Elliott Hughesa0664b92017-04-18 17:46:52 -07001291 for (i = 0; i < VG_DEEPEST_BACKTRACE; i++) {
sewardjb5f6f512005-03-10 23:59:00 +00001292 tmp_callers[i].ty = NoName;
philippe2c5c05e2012-07-26 21:37:36 +00001293 tmp_callers[i].name_is_simple_str = False;
sewardjb5f6f512005-03-10 23:59:00 +00001294 tmp_callers[i].name = NULL;
1295 }
1296
njn810086f2002-11-14 12:42:47 +00001297 supp->string = supp->extra = NULL;
sewardjde4a1d02002-03-22 01:27:54 +00001298
philippe2193a7c2012-12-08 17:54:16 +00001299 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
philippe7d69fd92012-02-26 21:26:00 +00001300 if (eof) {
florian77eb20b2014-09-11 21:19:17 +00001301 VG_(free)(supp);
philippe7d69fd92012-02-26 21:26:00 +00001302 break;
1303 }
sewardjde4a1d02002-03-22 01:27:54 +00001304
sewardjb5f6f512005-03-10 23:59:00 +00001305 if (!VG_STREQ(buf, "{")) BOMB("expected '{' or end-of-file");
sewardjde4a1d02002-03-22 01:27:54 +00001306
philippe2193a7c2012-12-08 17:54:16 +00001307 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
sewardjb5f6f512005-03-10 23:59:00 +00001308
1309 if (eof || VG_STREQ(buf, "}")) BOMB("unexpected '}'");
1310
florian77eb20b2014-09-11 21:19:17 +00001311 supp->sname = VG_(strdup)("errormgr.losf.2", buf);
philippe362441d2013-07-22 22:00:13 +00001312 supp->clo_suppressions_i = clo_suppressions_i;
1313 supp->sname_lineno = lineno;
sewardjde4a1d02002-03-22 01:27:54 +00001314
philippe2193a7c2012-12-08 17:54:16 +00001315 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
njn25e49d8e72002-09-23 09:36:25 +00001316
philippe2193a7c2012-12-08 17:54:16 +00001317 if (eof) BOMB("unexpected end-of-file (expecting tool:suppr)");
sewardjde4a1d02002-03-22 01:27:54 +00001318
njn94065fd2004-11-22 19:26:27 +00001319 /* Check it has the "tool1,tool2,...:supp" form (look for ':') */
njnc40c3a82002-10-02 11:02:27 +00001320 i = 0;
1321 while (True) {
1322 if (buf[i] == ':') break;
sewardjb5f6f512005-03-10 23:59:00 +00001323 if (buf[i] == '\0') BOMB("malformed 'tool1,tool2,...:supp' line");
njnc40c3a82002-10-02 11:02:27 +00001324 i++;
njn25e49d8e72002-09-23 09:36:25 +00001325 }
njnc40c3a82002-10-02 11:02:27 +00001326 buf[i] = '\0'; /* Replace ':', splitting into two strings */
1327
nethercote7cc9c232004-01-21 15:08:04 +00001328 tool_names = & buf[0];
njn11cc9252002-10-07 14:42:59 +00001329 supp_name = & buf[i+1];
njnc40c3a82002-10-02 11:02:27 +00001330
nethercote7cc9c232004-01-21 15:08:04 +00001331 if (VG_(needs).core_errors && tool_name_present("core", tool_names))
njnc40c3a82002-10-02 11:02:27 +00001332 {
sewardjb5f6f512005-03-10 23:59:00 +00001333 // A core suppression
njna86f29e2006-12-14 02:55:58 +00001334 //(example code, see comment on CoreSuppKind above)
1335 //if (VG_STREQ(supp_name, "Thread"))
1336 // supp->skind = ThreadSupp;
1337 //else
sewardjb5f6f512005-03-10 23:59:00 +00001338 BOMB("unknown core suppression type");
njnc40c3a82002-10-02 11:02:27 +00001339 }
njn95ec8702004-11-22 16:46:13 +00001340 else if (VG_(needs).tool_errors &&
nethercote7cc9c232004-01-21 15:08:04 +00001341 tool_name_present(VG_(details).name, tool_names))
njnc40c3a82002-10-02 11:02:27 +00001342 {
sewardjb5f6f512005-03-10 23:59:00 +00001343 // A tool suppression
njn51d827b2005-05-09 01:02:08 +00001344 if (VG_TDICT_CALL(tool_recognised_suppression, supp_name, supp)) {
njn810086f2002-11-14 12:42:47 +00001345 /* Do nothing, function fills in supp->skind */
sewardjb5f6f512005-03-10 23:59:00 +00001346 } else {
1347 BOMB("unknown tool suppression type");
1348 }
njnc40c3a82002-10-02 11:02:27 +00001349 }
njn25e49d8e72002-09-23 09:36:25 +00001350 else {
sewardjb5f6f512005-03-10 23:59:00 +00001351 // Ignore rest of suppression
njn25e49d8e72002-09-23 09:36:25 +00001352 while (True) {
philippe2193a7c2012-12-08 17:54:16 +00001353 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1354 if (eof) BOMB("unexpected end-of-file (when skipping suppression)");
njn43c799e2003-04-08 00:08:52 +00001355 if (VG_STREQ(buf, "}"))
njn25e49d8e72002-09-23 09:36:25 +00001356 break;
1357 }
florian77eb20b2014-09-11 21:19:17 +00001358 VG_(free)(supp->sname);
1359 VG_(free)(supp);
njn25e49d8e72002-09-23 09:36:25 +00001360 continue;
sewardjde4a1d02002-03-22 01:27:54 +00001361 }
1362
philippe2193a7c2012-12-08 17:54:16 +00001363 buf[0] = 0;
1364 // tool_read_extra_suppression_info might read lines
1365 // from fd till a location line.
njn95ec8702004-11-22 16:46:13 +00001366 if (VG_(needs).tool_errors &&
sewardjd7a02db2008-12-12 08:07:49 +00001367 !VG_TDICT_CALL(tool_read_extra_suppression_info,
philippe362441d2013-07-22 22:00:13 +00001368 fd, &buf, &nBuf, &lineno, supp))
sewardjb5f6f512005-03-10 23:59:00 +00001369 {
1370 BOMB("bad or missing extra suppression info");
sewardjde4a1d02002-03-22 01:27:54 +00001371 }
1372
philippe2193a7c2012-12-08 17:54:16 +00001373 got_a_location_line_read_by_tool = buf[0] != 0 && is_location_line(buf);
1374
sewardj5e519302008-11-03 23:10:25 +00001375 /* the main frame-descriptor reading loop */
sewardjb5f6f512005-03-10 23:59:00 +00001376 i = 0;
1377 while (True) {
philippe2193a7c2012-12-08 17:54:16 +00001378 if (got_a_location_line_read_by_tool) {
1379 got_a_location_line_read_by_tool = False;
1380 eof = False;
1381 } else {
1382 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1383 }
sewardjb5f6f512005-03-10 23:59:00 +00001384 if (eof)
philippe2193a7c2012-12-08 17:54:16 +00001385 BOMB("unexpected end-of-file (when reading stack trace)");
sewardjb5f6f512005-03-10 23:59:00 +00001386 if (VG_STREQ(buf, "}")) {
1387 if (i > 0) {
1388 break;
1389 } else {
1390 BOMB("missing stack trace");
1391 }
1392 }
Elliott Hughesa0664b92017-04-18 17:46:52 -07001393 if (i == VG_DEEPEST_BACKTRACE)
sewardjb5f6f512005-03-10 23:59:00 +00001394 BOMB("too many callers in stack trace");
1395 if (i > 0 && i >= VG_(clo_backtrace_size))
1396 break;
philippe7d69fd92012-02-26 21:26:00 +00001397 if (!setLocationTy(&(tmp_callers[i]), buf))
sewardj5e519302008-11-03 23:10:25 +00001398 BOMB("location should be \"...\", or should start "
1399 "with \"fun:\" or \"obj:\"");
sewardjb5f6f512005-03-10 23:59:00 +00001400 i++;
1401 }
1402
1403 // If the num callers is >= VG_(clo_backtrace_size), ignore any extra
1404 // lines and grab the '}'.
sewardj57a8f5f2003-07-06 01:40:11 +00001405 if (!VG_STREQ(buf, "}")) {
sewardjb5f6f512005-03-10 23:59:00 +00001406 do {
philippe2193a7c2012-12-08 17:54:16 +00001407 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
sewardjb5f6f512005-03-10 23:59:00 +00001408 } while (!eof && !VG_STREQ(buf, "}"));
1409 }
1410
sewardj5e519302008-11-03 23:10:25 +00001411 // Reject entries which are entirely composed of frame
1412 // level wildcards.
1413 vg_assert(i > 0); // guaranteed by frame-descriptor reading loop
1414 for (j = 0; j < i; j++) {
1415 if (tmp_callers[j].ty == FunName || tmp_callers[j].ty == ObjName)
1416 break;
1417 vg_assert(tmp_callers[j].ty == DotDotDot);
1418 }
1419 vg_assert(j >= 0 && j <= i);
1420 if (j == i) {
1421 // we didn't find any non-"..." entries
1422 BOMB("suppression must contain at least one location "
1423 "line which is not \"...\"");
1424 }
1425
sewardjb5f6f512005-03-10 23:59:00 +00001426 // Copy tmp_callers[] into supp->callers[]
1427 supp->n_callers = i;
florian77eb20b2014-09-11 21:19:17 +00001428 supp->callers = VG_(malloc)("errormgr.losf.4", i * sizeof(SuppLoc));
sewardjb5f6f512005-03-10 23:59:00 +00001429 for (i = 0; i < supp->n_callers; i++) {
1430 supp->callers[i] = tmp_callers[i];
sewardj57a8f5f2003-07-06 01:40:11 +00001431 }
1432
njn695c16e2005-03-27 03:40:28 +00001433 supp->next = suppressions;
1434 suppressions = supp;
sewardjde4a1d02002-03-22 01:27:54 +00001435 }
njn35db56c2009-07-24 07:38:29 +00001436 VG_(free)(buf);
sewardjde4a1d02002-03-22 01:27:54 +00001437 VG_(close)(fd);
1438 return;
1439
1440 syntax_error:
sewardjf349d552005-11-14 17:01:01 +00001441 if (VG_(clo_xml))
sewardj09361bf2011-01-28 00:19:25 +00001442 VG_(printf_xml)("</valgrindoutput>\n");
sewardj738856f2009-07-15 14:48:32 +00001443 VG_(umsg)("FATAL: in suppressions file \"%s\" near line %d:\n",
njn6f74a7e2009-03-12 00:06:45 +00001444 filename, lineno );
sewardj738856f2009-07-15 14:48:32 +00001445 VG_(umsg)(" %s\n", err_str );
sewardjb5f6f512005-03-10 23:59:00 +00001446
sewardjde4a1d02002-03-22 01:27:54 +00001447 VG_(close)(fd);
sewardj738856f2009-07-15 14:48:32 +00001448 VG_(umsg)("exiting now.\n");
nethercote8ed8a892004-11-08 13:24:25 +00001449 VG_(exit)(1);
sewardjde4a1d02002-03-22 01:27:54 +00001450
sewardjb5f6f512005-03-10 23:59:00 +00001451# undef BOMB
sewardjde4a1d02002-03-22 01:27:54 +00001452}
1453
1454
1455void VG_(load_suppressions) ( void )
1456{
1457 Int i;
njn695c16e2005-03-27 03:40:28 +00001458 suppressions = NULL;
florian79316272014-10-07 18:36:28 +00001459 for (i = 0; i < VG_(sizeXA)(VG_(clo_suppressions)); i++) {
sewardjde4a1d02002-03-22 01:27:54 +00001460 if (VG_(clo_verbosity) > 1) {
sewardj738856f2009-07-15 14:48:32 +00001461 VG_(dmsg)("Reading suppressions file: %s\n",
florian79316272014-10-07 18:36:28 +00001462 *(HChar**) VG_(indexXA)(VG_(clo_suppressions), i));
sewardjde4a1d02002-03-22 01:27:54 +00001463 }
philippe362441d2013-07-22 22:00:13 +00001464 load_one_suppressions_file( i );
sewardjde4a1d02002-03-22 01:27:54 +00001465 }
1466}
1467
sewardjd7a02db2008-12-12 08:07:49 +00001468
1469/*------------------------------------------------------------*/
1470/*--- Matching errors to suppressions ---*/
1471/*------------------------------------------------------------*/
1472
1473/* Parameterising functions for the use of VG_(generic_match) in
1474 suppression-vs-error matching. The suppression frames (SuppLoc)
1475 play the role of 'pattern'-element, and the error frames (IPs,
1476 hence simply Addrs) play the role of 'input'. In short then, we're
1477 matching a sequence of Addrs against a pattern composed of a
1478 sequence of SuppLocs.
1479*/
florian3e798632012-11-24 19:41:54 +00001480static Bool supploc_IsStar ( const void* supplocV )
sewardjd7a02db2008-12-12 08:07:49 +00001481{
florian3e798632012-11-24 19:41:54 +00001482 const SuppLoc* supploc = supplocV;
sewardjd7a02db2008-12-12 08:07:49 +00001483 return supploc->ty == DotDotDot;
1484}
1485
florian3e798632012-11-24 19:41:54 +00001486static Bool supploc_IsQuery ( const void* supplocV )
sewardjd7a02db2008-12-12 08:07:49 +00001487{
1488 return False; /* there's no '?' equivalent in the supp syntax */
1489}
1490
philippe13a59522012-08-03 23:11:39 +00001491/* IPtoFunOrObjCompleter is a lazy completer of the IPs
1492 needed to match an error with the suppression patterns.
1493 The matching between an IP and a suppression pattern is done either
1494 with the IP function name or with the IP object name.
1495 First time the fun or obj name is needed for an IP member
1496 of a stack trace, it will be computed and stored in names.
philippea0a73932014-06-15 15:42:20 +00001497 Also, if the IP corresponds to one or more inlined function calls,
1498 the inlined function names are expanded.
philippe13a59522012-08-03 23:11:39 +00001499 The IPtoFunOrObjCompleter type is designed to minimise the nr of
1500 allocations and the nr of debuginfo search. */
1501typedef
1502 struct {
1503 StackTrace ips; // stack trace we are lazily completing.
1504 UWord n_ips; // nr of elements in ips.
1505
philippea0a73932014-06-15 15:42:20 +00001506 // VG_(generic_match) calls haveInputInpC to check
1507 // for the presence of an input element identified by ixInput
1508 // (i.e. a number that identifies the ixInput element of the
1509 // input sequence). It calls supp_pattEQinp to match this input
1510 // element with a pattern.
1511 // When inlining info is used to provide inlined function calls
1512 // in stacktraces, one IP in ips can be expanded in several
1513 // function names. So, each time input (or presence of input)
1514 // is requested by VG_(generic_match), we will expand
1515 // more IP of ips till we have expanded enough to reach the
1516 // input element requested (or we cannot expand anymore).
1517
1518 UWord n_ips_expanded;
1519 // n_ips_expanded maintains the nr of elements in ips that we have
1520 // already expanded.
1521 UWord n_expanded;
1522 // n_expanded maintains the nr of elements resulting from the expansion
1523 // of the n_ips_expanded IPs. Without inlined function calls,
1524 // n_expanded == n_ips_expanded. With inlining info,
1525 // n_expanded >= n_ips_expanded.
1526
1527 Int* n_offsets_per_ip;
philippec06f6842014-07-30 22:20:29 +00001528 // n_offsets_per_ip[i] gives the nr of offsets in fun_offsets and
1529 // obj_offsets resulting of the expansion of ips[i].
philippea0a73932014-06-15 15:42:20 +00001530 // The sum of all n_expanded_per_ip must be equal to n_expanded.
philippec06f6842014-07-30 22:20:29 +00001531 // This array allows to retrieve the position in ips corresponding to
1532 // an ixInput.
philippea0a73932014-06-15 15:42:20 +00001533
1534 // size (in elements) of fun_offsets and obj_offsets.
1535 // (fun|obj)_offsets are reallocated if more space is needed
1536 // to expand an IP.
1537 UWord sz_offsets;
1538
philippe13a59522012-08-03 23:11:39 +00001539 Int* fun_offsets;
philippea0a73932014-06-15 15:42:20 +00001540 // fun_offsets[ixInput] is the offset in names where the
1541 // function name for the ixInput element of the input sequence
1542 // can be found. As one IP of ips can be expanded in several
1543 // function calls due to inlined function calls, we can have more
1544 // elements in fun_offsets than in ips.
1545 // An offset -1 means the function name has not yet been computed.
philippe13a59522012-08-03 23:11:39 +00001546 Int* obj_offsets;
philippea0a73932014-06-15 15:42:20 +00001547 // Similarly, obj_offsets[ixInput] gives the offset for the
1548 // object name for ips[ixInput]
1549 // (-1 meaning object name not yet been computed).
philippe13a59522012-08-03 23:11:39 +00001550
1551 // All function names and object names will be concatenated
1552 // in names. names is reallocated on demand.
florian19f91bb2012-11-10 22:29:54 +00001553 HChar *names;
philippe13a59522012-08-03 23:11:39 +00001554 Int names_szB; // size of names.
florian19f91bb2012-11-10 22:29:54 +00001555 Int names_free; // offset first free HChar in names.
philippe13a59522012-08-03 23:11:39 +00001556 }
1557 IPtoFunOrObjCompleter;
1558
florian518850b2014-10-22 22:25:30 +00001559static void pp_ip2fo (const IPtoFunOrObjCompleter* ip2fo)
philippe13a59522012-08-03 23:11:39 +00001560{
philippe5ab7ce82014-06-24 20:48:25 +00001561 Int i, j;
1562 Int o;
1563
1564 VG_(printf)("n_ips %lu n_ips_expanded %lu resulting in n_expanded %lu\n",
1565 ip2fo->n_ips, ip2fo->n_ips_expanded, ip2fo->n_expanded);
1566 for (i = 0; i < ip2fo->n_ips_expanded; i++) {
1567 o = 0;
1568 for (j = 0; j < i; j++)
1569 o += ip2fo->n_offsets_per_ip[j];
1570 VG_(printf)("ips %d 0x08%lx offset [%d,%d] ",
1571 i, ip2fo->ips[i],
1572 o, o+ip2fo->n_offsets_per_ip[i]-1);
1573 for (j = 0; j < ip2fo->n_offsets_per_ip[i]; j++) {
1574 VG_(printf)("%sfun:%s obj:%s\n",
1575 j == 0 ? "" : " ",
1576 ip2fo->fun_offsets[o+j] == -1 ?
1577 "<not expanded>" : &ip2fo->names[ip2fo->fun_offsets[o+j]],
1578 ip2fo->obj_offsets[o+j] == -1 ?
1579 "<not expanded>" : &ip2fo->names[ip2fo->obj_offsets[o+j]]);
1580 }
1581 }
1582}
1583
1584/* free the memory in ip2fo.
philippec06f6842014-07-30 22:20:29 +00001585 At debuglog 4, su (or NULL) will be used to show the matching
1586 (or non matching) with ip2fo. */
florian518850b2014-10-22 22:25:30 +00001587static void clearIPtoFunOrObjCompleter ( const Supp *su,
philippec06f6842014-07-30 22:20:29 +00001588 IPtoFunOrObjCompleter* ip2fo)
philippe5ab7ce82014-06-24 20:48:25 +00001589{
1590 if (DEBUG_ERRORMGR || VG_(debugLog_getLevel)() >= 4) {
florian79316272014-10-07 18:36:28 +00001591 if (su) {
1592 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1593 su->clo_suppressions_i);
philippe5ab7ce82014-06-24 20:48:25 +00001594 VG_(dmsg)("errormgr matching end suppression %s %s:%d matched:\n",
1595 su->sname,
florian79316272014-10-07 18:36:28 +00001596 filename,
philippe5ab7ce82014-06-24 20:48:25 +00001597 su->sname_lineno);
florian79316272014-10-07 18:36:28 +00001598 } else
philippe5ab7ce82014-06-24 20:48:25 +00001599 VG_(dmsg)("errormgr matching end no suppression matched:\n");
1600 VG_(pp_StackTrace) (ip2fo->ips, ip2fo->n_ips);
1601 pp_ip2fo(ip2fo);
1602 }
philippea0a73932014-06-15 15:42:20 +00001603 if (ip2fo->n_offsets_per_ip) VG_(free)(ip2fo->n_offsets_per_ip);
1604 if (ip2fo->fun_offsets) VG_(free)(ip2fo->fun_offsets);
1605 if (ip2fo->obj_offsets) VG_(free)(ip2fo->obj_offsets);
1606 if (ip2fo->names) VG_(free)(ip2fo->names);
philippe13a59522012-08-03 23:11:39 +00001607}
1608
florian46cc0452014-10-25 19:20:38 +00001609/* Grow ip2fo->names to ensure we have NEEDED characters available
philippea0a73932014-06-15 15:42:20 +00001610 in ip2fo->names and returns a pointer to the first free char. */
florian46cc0452014-10-25 19:20:38 +00001611static HChar* grow_names(IPtoFunOrObjCompleter* ip2fo, SizeT needed)
philippe13a59522012-08-03 23:11:39 +00001612{
philippea0a73932014-06-15 15:42:20 +00001613 if (ip2fo->names_szB
florian46cc0452014-10-25 19:20:38 +00001614 < ip2fo->names_free + needed) {
1615 if (needed < ERRTXT_LEN) needed = ERRTXT_LEN;
1616
philippea0a73932014-06-15 15:42:20 +00001617 ip2fo->names
1618 = VG_(realloc)("foc_names",
1619 ip2fo->names,
florian46cc0452014-10-25 19:20:38 +00001620 ip2fo->names_szB + needed);
1621 ip2fo->names_szB += needed;
philippea0a73932014-06-15 15:42:20 +00001622 }
1623 return ip2fo->names + ip2fo->names_free;
1624}
1625
1626/* foComplete returns the function name or object name for ixInput.
1627 If needFun, returns the function name for this input
1628 else returns the object name for this input.
1629 The function name or object name will be computed and added in
1630 names if not yet done. */
1631static HChar* foComplete(IPtoFunOrObjCompleter* ip2fo,
1632 Int ixInput, Bool needFun)
1633{
1634 vg_assert (ixInput < ip2fo->n_expanded);
1635 vg_assert (VG_(clo_read_inline_info) || ixInput < ip2fo->n_ips);
philippe13a59522012-08-03 23:11:39 +00001636
1637 // ptr to the offset array for function offsets (if needFun)
1638 // or object offsets (if !needFun).
1639 Int** offsets;
1640 if (needFun)
1641 offsets = &ip2fo->fun_offsets;
1642 else
1643 offsets = &ip2fo->obj_offsets;
1644
philippe13a59522012-08-03 23:11:39 +00001645 // Complete Fun name or Obj name for IP if not yet done.
philippea0a73932014-06-15 15:42:20 +00001646 if ((*offsets)[ixInput] == -1) {
florian46cc0452014-10-25 19:20:38 +00001647 const HChar* caller;
1648
philippea0a73932014-06-15 15:42:20 +00001649 (*offsets)[ixInput] = ip2fo->names_free;
philippe5ab7ce82014-06-24 20:48:25 +00001650 if (DEBUG_ERRORMGR) VG_(printf)("marking %s ixInput %d offset %d\n",
1651 needFun ? "fun" : "obj",
1652 ixInput, ip2fo->names_free);
philippe13a59522012-08-03 23:11:39 +00001653 if (needFun) {
philippea0a73932014-06-15 15:42:20 +00001654 // With inline info, fn names must have been completed already.
1655 vg_assert (!VG_(clo_read_inline_info));
philippe13a59522012-08-03 23:11:39 +00001656 /* Get the function name into 'caller_name', or "???"
1657 if unknown. */
1658 // Nb: C++-mangled names are used in suppressions. Do, though,
1659 // Z-demangle them, since otherwise it's possible to wind
1660 // up comparing "malloc" in the suppression against
1661 // "_vgrZU_libcZdsoZa_malloc" in the backtrace, and the
1662 // two of them need to be made to match.
philippea0a73932014-06-15 15:42:20 +00001663 if (!VG_(get_fnname_no_cxx_demangle)(ip2fo->ips[ixInput],
florian46cc0452014-10-25 19:20:38 +00001664 &caller,
philippea0a73932014-06-15 15:42:20 +00001665 NULL))
florian46cc0452014-10-25 19:20:38 +00001666 caller = "???";
philippe13a59522012-08-03 23:11:39 +00001667 } else {
1668 /* Get the object name into 'caller_name', or "???"
1669 if unknown. */
philippea0a73932014-06-15 15:42:20 +00001670 UWord i;
1671 UWord last_expand_pos_ips = 0;
1672 UWord pos_ips;
1673
1674 /* First get the pos in ips corresponding to ixInput */
1675 for (pos_ips = 0; pos_ips < ip2fo->n_expanded; pos_ips++) {
1676 last_expand_pos_ips += ip2fo->n_offsets_per_ip[pos_ips];
philippe5ab7ce82014-06-24 20:48:25 +00001677 if (ixInput < last_expand_pos_ips)
philippea0a73932014-06-15 15:42:20 +00001678 break;
1679 }
1680 /* pos_ips is the position in ips corresponding to ixInput.
1681 last_expand_pos_ips is the last offset in fun/obj where
1682 ips[pos_ips] has been expanded. */
1683
florian46cc0452014-10-25 19:20:38 +00001684 if (!VG_(get_objname)(ip2fo->ips[pos_ips], &caller))
1685 caller = "???";
philippea0a73932014-06-15 15:42:20 +00001686
1687 // Have all inlined calls pointing at this object name
philippe5ab7ce82014-06-24 20:48:25 +00001688 for (i = last_expand_pos_ips - ip2fo->n_offsets_per_ip[pos_ips] + 1;
1689 i < last_expand_pos_ips;
1690 i++) {
philippea0a73932014-06-15 15:42:20 +00001691 ip2fo->obj_offsets[i] = ip2fo->names_free;
philippe5ab7ce82014-06-24 20:48:25 +00001692 if (DEBUG_ERRORMGR)
philippec06f6842014-07-30 22:20:29 +00001693 VG_(printf) (" set obj_offset %lu to %d\n",
1694 i, ip2fo->names_free);
philippe5ab7ce82014-06-24 20:48:25 +00001695 }
philippe13a59522012-08-03 23:11:39 +00001696 }
florian46cc0452014-10-25 19:20:38 +00001697 SizeT caller_len = VG_(strlen)(caller);
1698 HChar* caller_name = grow_names(ip2fo, caller_len + 1);
1699 VG_(strcpy)(caller_name, caller);
1700 ip2fo->names_free += caller_len + 1;
philippe5ab7ce82014-06-24 20:48:25 +00001701 if (DEBUG_ERRORMGR) pp_ip2fo(ip2fo);
philippe13a59522012-08-03 23:11:39 +00001702 }
1703
philippea0a73932014-06-15 15:42:20 +00001704 return ip2fo->names + (*offsets)[ixInput];
1705}
1706
1707// Grow fun and obj _offsets arrays to have at least n_req elements.
1708// Ensure n_offsets_per_ip is allocated.
1709static void grow_offsets(IPtoFunOrObjCompleter* ip2fo, Int n_req)
1710{
1711 Int i;
1712
1713 // n_offsets_per_ip must always have the size of the ips array
1714 if (ip2fo->n_offsets_per_ip == NULL) {
1715 ip2fo->n_offsets_per_ip = VG_(malloc)("grow_offsets",
1716 ip2fo->n_ips * sizeof(Int));
1717 for (i = 0; i < ip2fo->n_ips; i++)
1718 ip2fo->n_offsets_per_ip[i] = 0;
1719 }
1720
1721 if (ip2fo->sz_offsets >= n_req)
1722 return;
1723
1724 // Avoid too much re-allocation by allocating at least ip2fo->n_ips
1725 // elements and at least a few more elements than the current size.
1726 if (n_req < ip2fo->n_ips)
1727 n_req = ip2fo->n_ips;
1728 if (n_req < ip2fo->sz_offsets + 5)
1729 n_req = ip2fo->sz_offsets + 5;
1730
1731 ip2fo->fun_offsets = VG_(realloc)("grow_offsets", ip2fo->fun_offsets,
1732 n_req * sizeof(Int));
1733 for (i = ip2fo->sz_offsets; i < n_req; i++)
1734 ip2fo->fun_offsets[i] = -1;
1735
1736 ip2fo->obj_offsets = VG_(realloc)("grow_offsets", ip2fo->obj_offsets,
1737 n_req * sizeof(Int));
1738 for (i = ip2fo->sz_offsets; i < n_req; i++)
1739 ip2fo->obj_offsets[i] = -1;
1740
1741 ip2fo->sz_offsets = n_req;
1742}
1743
1744// Expands more IPs from ip2fo->ips.
1745static void expandInput (IPtoFunOrObjCompleter* ip2fo, UWord ixInput )
1746{
1747 while (ip2fo->n_ips_expanded < ip2fo->n_ips
1748 && ip2fo->n_expanded <= ixInput) {
1749 if (VG_(clo_read_inline_info)) {
1750 // Expand one more IP in one or more calls.
1751 const Addr IP = ip2fo->ips[ip2fo->n_ips_expanded];
1752 InlIPCursor *iipc;
1753
1754 iipc = VG_(new_IIPC)(IP);
1755 // The only thing we really need is the nr of inlined fn calls
1756 // corresponding to the IP we will expand.
1757 // However, computing this is mostly the same as finding
1758 // the function name. So, let's directly complete the function name.
1759 do {
florian46cc0452014-10-25 19:20:38 +00001760 const HChar *caller;
philippea0a73932014-06-15 15:42:20 +00001761 grow_offsets(ip2fo, ip2fo->n_expanded+1);
1762 ip2fo->fun_offsets[ip2fo->n_expanded] = ip2fo->names_free;
1763 if (!VG_(get_fnname_no_cxx_demangle)(IP,
florian46cc0452014-10-25 19:20:38 +00001764 &caller,
philippea0a73932014-06-15 15:42:20 +00001765 iipc))
florian46cc0452014-10-25 19:20:38 +00001766 caller = "???";
1767 SizeT caller_len = VG_(strlen)(caller);
1768 HChar* caller_name = grow_names(ip2fo, caller_len + 1);
1769 VG_(strcpy)(caller_name, caller);
1770 ip2fo->names_free += caller_len + 1;
philippea0a73932014-06-15 15:42:20 +00001771 ip2fo->n_expanded++;
1772 ip2fo->n_offsets_per_ip[ip2fo->n_ips_expanded]++;
1773 } while (VG_(next_IIPC)(iipc));
1774 ip2fo->n_ips_expanded++;
1775 VG_(delete_IIPC) (iipc);
1776 } else {
1777 // Without inlined fn call info, expansion simply
1778 // consists in allocating enough elements in (fun|obj)_offsets.
1779 // The function or object names themselves will be completed
1780 // when requested.
1781 Int i;
1782 grow_offsets(ip2fo, ip2fo->n_ips);
1783 ip2fo->n_ips_expanded = ip2fo->n_ips;
1784 ip2fo->n_expanded = ip2fo->n_ips;
1785 for (i = 0; i < ip2fo->n_ips; i++)
1786 ip2fo->n_offsets_per_ip[i] = 1;
1787 }
1788 }
1789}
1790
1791static Bool haveInputInpC (void* inputCompleter, UWord ixInput )
1792{
1793 IPtoFunOrObjCompleter* ip2fo = inputCompleter;
1794 expandInput(ip2fo, ixInput);
1795 return ixInput < ip2fo->n_expanded;
philippe13a59522012-08-03 23:11:39 +00001796}
1797
florian3e798632012-11-24 19:41:54 +00001798static Bool supp_pattEQinp ( const void* supplocV, const void* addrV,
philippea0a73932014-06-15 15:42:20 +00001799 void* inputCompleter, UWord ixInput )
sewardjd7a02db2008-12-12 08:07:49 +00001800{
florian3e798632012-11-24 19:41:54 +00001801 const SuppLoc* supploc = supplocV; /* PATTERN */
florian3e798632012-11-24 19:41:54 +00001802 IPtoFunOrObjCompleter* ip2fo = inputCompleter;
florian19f91bb2012-11-10 22:29:54 +00001803 HChar* funobj_name; // Fun or Obj name.
philippe5ab7ce82014-06-24 20:48:25 +00001804 Bool ret;
sewardjd7a02db2008-12-12 08:07:49 +00001805
philippea0a73932014-06-15 15:42:20 +00001806 expandInput(ip2fo, ixInput);
1807 vg_assert(ixInput < ip2fo->n_expanded);
1808
sewardjd7a02db2008-12-12 08:07:49 +00001809 /* So, does this IP address match this suppression-line? */
1810 switch (supploc->ty) {
1811 case DotDotDot:
1812 /* supp_pattEQinp is a callback from VG_(generic_match). As
1813 per the spec thereof (see include/pub_tool_seqmatch.h), we
1814 should never get called with a pattern value for which the
1815 _IsStar or _IsQuery function would return True. Hence
1816 this can't happen. */
1817 vg_assert(0);
1818 case ObjName:
philippea0a73932014-06-15 15:42:20 +00001819 funobj_name = foComplete(ip2fo, ixInput, False /*needFun*/);
sewardjd7a02db2008-12-12 08:07:49 +00001820 break;
philippe13a59522012-08-03 23:11:39 +00001821 case FunName:
philippea0a73932014-06-15 15:42:20 +00001822 funobj_name = foComplete(ip2fo, ixInput, True /*needFun*/);
sewardjd7a02db2008-12-12 08:07:49 +00001823 break;
1824 default:
1825 vg_assert(0);
1826 }
1827
philippe13a59522012-08-03 23:11:39 +00001828 /* So now we have the function or object name in funobj_name, and
sewardjd7a02db2008-12-12 08:07:49 +00001829 the pattern (at the character level) to match against is in
1830 supploc->name. Hence (and leading to a re-entrant call of
philippe2c5c05e2012-07-26 21:37:36 +00001831 VG_(generic_match) if there is a wildcard character): */
1832 if (supploc->name_is_simple_str)
philippe5ab7ce82014-06-24 20:48:25 +00001833 ret = VG_(strcmp) (supploc->name, funobj_name) == 0;
philippe2c5c05e2012-07-26 21:37:36 +00001834 else
philippe5ab7ce82014-06-24 20:48:25 +00001835 ret = VG_(string_match)(supploc->name, funobj_name);
1836 if (DEBUG_ERRORMGR)
1837 VG_(printf) ("supp_pattEQinp %s patt %s ixUnput %lu value:%s match:%s\n",
1838 supploc->ty == FunName ? "fun" : "obj",
1839 supploc->name, ixInput, funobj_name,
1840 ret ? "yes" : "no");
1841 return ret;
sewardjd7a02db2008-12-12 08:07:49 +00001842}
1843
1844/////////////////////////////////////////////////////
1845
florian518850b2014-10-22 22:25:30 +00001846static Bool supp_matches_callers(IPtoFunOrObjCompleter* ip2fo,
1847 const Supp* su)
sewardjd7a02db2008-12-12 08:07:49 +00001848{
1849 /* Unwrap the args and set up the correct parameterisation of
1850 VG_(generic_match), using supploc_IsStar, supploc_IsQuery and
1851 supp_pattEQinp. */
philippe13a59522012-08-03 23:11:39 +00001852 /* note, StackTrace ip2fo->ips === Addr* */
sewardjd7a02db2008-12-12 08:07:49 +00001853 SuppLoc* supps = su->callers;
1854 UWord n_supps = su->n_callers;
1855 UWord szbPatt = sizeof(SuppLoc);
sewardjd7a02db2008-12-12 08:07:49 +00001856 Bool matchAll = False; /* we just want to match a prefix */
florian79316272014-10-07 18:36:28 +00001857 if (DEBUG_ERRORMGR) {
1858 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1859 su->clo_suppressions_i);
philippe5ab7ce82014-06-24 20:48:25 +00001860 VG_(dmsg)(" errormgr Checking match with %s %s:%d\n",
1861 su->sname,
florian79316272014-10-07 18:36:28 +00001862 filename,
philippe5ab7ce82014-06-24 20:48:25 +00001863 su->sname_lineno);
florian79316272014-10-07 18:36:28 +00001864 }
sewardjd7a02db2008-12-12 08:07:49 +00001865 return
1866 VG_(generic_match)(
1867 matchAll,
philippea0a73932014-06-15 15:42:20 +00001868 /*PATT*/supps, szbPatt, n_supps, 0/*initial ixPatt*/,
1869 /*INPUT*/
1870 NULL, 0, 0, /* input/szbInput/nInput 0, as using an inputCompleter */
1871 0/*initial ixInput*/,
philippe13a59522012-08-03 23:11:39 +00001872 supploc_IsStar, supploc_IsQuery, supp_pattEQinp,
philippea0a73932014-06-15 15:42:20 +00001873 ip2fo, haveInputInpC
sewardjd7a02db2008-12-12 08:07:49 +00001874 );
1875}
1876
1877/////////////////////////////////////////////////////
1878
sewardjb5f6f512005-03-10 23:59:00 +00001879static
florian518850b2014-10-22 22:25:30 +00001880Bool supp_matches_error(const Supp* su, const Error* err)
njn25e49d8e72002-09-23 09:36:25 +00001881{
njn810086f2002-11-14 12:42:47 +00001882 switch (su->skind) {
njna86f29e2006-12-14 02:55:58 +00001883 //(example code, see comment on CoreSuppKind above)
1884 //case ThreadSupp:
1885 // return (err->ekind == ThreadErr);
njn25e49d8e72002-09-23 09:36:25 +00001886 default:
njn95ec8702004-11-22 16:46:13 +00001887 if (VG_(needs).tool_errors) {
njn51d827b2005-05-09 01:02:08 +00001888 return VG_TDICT_CALL(tool_error_matches_suppression, err, su);
njn25e49d8e72002-09-23 09:36:25 +00001889 } else {
1890 VG_(printf)(
njn95ec8702004-11-22 16:46:13 +00001891 "\nUnhandled suppression type: %u. VG_(needs).tool_errors\n"
njn25e49d8e72002-09-23 09:36:25 +00001892 "probably needs to be set.\n",
floriana5e06c32015-08-05 21:16:09 +00001893 (UInt)err->ekind);
floriana4ca4fe2014-09-16 09:28:12 +00001894 VG_(core_panic)("unhandled suppression type");
njn25e49d8e72002-09-23 09:36:25 +00001895 }
1896 }
1897}
1898
sewardjd7a02db2008-12-12 08:07:49 +00001899/////////////////////////////////////////////////////
sewardj5e519302008-11-03 23:10:25 +00001900
njn810086f2002-11-14 12:42:47 +00001901/* Does an error context match a suppression? ie is this a suppressible
1902 error? If so, return a pointer to the Supp record, otherwise NULL.
njn25e49d8e72002-09-23 09:36:25 +00001903 Tries to minimise the number of symbol searches since they are expensive.
sewardjde4a1d02002-03-22 01:27:54 +00001904*/
florian518850b2014-10-22 22:25:30 +00001905static Supp* is_suppressible_error ( const Error* err )
sewardjde4a1d02002-03-22 01:27:54 +00001906{
njn810086f2002-11-14 12:42:47 +00001907 Supp* su;
sewardj8a7d4e42006-10-17 01:41:17 +00001908 Supp* su_prev;
1909
philippe13a59522012-08-03 23:11:39 +00001910 IPtoFunOrObjCompleter ip2fo;
1911 /* Conceptually, ip2fo contains an array of function names and an array of
1912 object names, corresponding to the array of IP of err->where.
1913 These names are just computed 'on demand' (so once maximum),
philippe4e32d672013-10-17 22:10:41 +00001914 then stored (efficiently, avoiding too many allocs) in ip2fo to be
1915 re-usable for the matching of the same IP with the next suppression
1916 pattern.
philippe13a59522012-08-03 23:11:39 +00001917
1918 VG_(generic_match) gets this 'IP to Fun or Obj name completer' as one
1919 of its arguments. It will then pass it to the function
1920 supp_pattEQinp which will then lazily complete the IP function name or
1921 object name inside ip2fo. Next time the fun or obj name for the same
1922 IP is needed (i.e. for the matching with the next suppr pattern), then
1923 the fun or obj name will not be searched again in the debug info. */
1924
sewardj8a7d4e42006-10-17 01:41:17 +00001925 /* stats gathering */
1926 em_supplist_searches++;
sewardjde4a1d02002-03-22 01:27:54 +00001927
philippe13a59522012-08-03 23:11:39 +00001928 /* Prepare the lazy input completer. */
1929 ip2fo.ips = VG_(get_ExeContext_StackTrace)(err->where);
1930 ip2fo.n_ips = VG_(get_ExeContext_n_ips)(err->where);
philippea0a73932014-06-15 15:42:20 +00001931 ip2fo.n_ips_expanded = 0;
1932 ip2fo.n_expanded = 0;
1933 ip2fo.sz_offsets = 0;
1934 ip2fo.n_offsets_per_ip = NULL;
philippe13a59522012-08-03 23:11:39 +00001935 ip2fo.fun_offsets = NULL;
1936 ip2fo.obj_offsets = NULL;
1937 ip2fo.names = NULL;
1938 ip2fo.names_szB = 0;
1939 ip2fo.names_free = 0;
1940
sewardjde4a1d02002-03-22 01:27:54 +00001941 /* See if the error context matches any suppression. */
philippe5ab7ce82014-06-24 20:48:25 +00001942 if (DEBUG_ERRORMGR || VG_(debugLog_getLevel)() >= 4)
1943 VG_(dmsg)("errormgr matching begin\n");
sewardj8a7d4e42006-10-17 01:41:17 +00001944 su_prev = NULL;
njn695c16e2005-03-27 03:40:28 +00001945 for (su = suppressions; su != NULL; su = su->next) {
sewardj8a7d4e42006-10-17 01:41:17 +00001946 em_supplist_cmps++;
philippe13a59522012-08-03 23:11:39 +00001947 if (supp_matches_error(su, err)
1948 && supp_matches_callers(&ip2fo, su)) {
philippe4e32d672013-10-17 22:10:41 +00001949 /* got a match. */
1950 /* Inform the tool that err is suppressed by su. */
1951 (void)VG_TDICT_CALL(tool_update_extra_suppression_use, err, su);
1952 /* Move this entry to the head of the list
sewardj8a7d4e42006-10-17 01:41:17 +00001953 in the hope of making future searches cheaper. */
1954 if (su_prev) {
1955 vg_assert(su_prev->next == su);
1956 su_prev->next = su->next;
1957 su->next = suppressions;
1958 suppressions = su;
1959 }
philippe5ab7ce82014-06-24 20:48:25 +00001960 clearIPtoFunOrObjCompleter(su, &ip2fo);
njn25e49d8e72002-09-23 09:36:25 +00001961 return su;
sewardjde4a1d02002-03-22 01:27:54 +00001962 }
sewardj8a7d4e42006-10-17 01:41:17 +00001963 su_prev = su;
sewardjde4a1d02002-03-22 01:27:54 +00001964 }
philippe5ab7ce82014-06-24 20:48:25 +00001965 clearIPtoFunOrObjCompleter(NULL, &ip2fo);
njn25e49d8e72002-09-23 09:36:25 +00001966 return NULL; /* no matches */
sewardjde4a1d02002-03-22 01:27:54 +00001967}
1968
sewardj8a7d4e42006-10-17 01:41:17 +00001969/* Show accumulated error-list and suppression-list search stats.
1970*/
1971void VG_(print_errormgr_stats) ( void )
1972{
sewardj738856f2009-07-15 14:48:32 +00001973 VG_(dmsg)(
1974 " errormgr: %'lu supplist searches, %'lu comparisons during search\n",
sewardj8a7d4e42006-10-17 01:41:17 +00001975 em_supplist_searches, em_supplist_cmps
1976 );
sewardj738856f2009-07-15 14:48:32 +00001977 VG_(dmsg)(
1978 " errormgr: %'lu errlist searches, %'lu comparisons during search\n",
sewardj8a7d4e42006-10-17 01:41:17 +00001979 em_errlist_searches, em_errlist_cmps
1980 );
1981}
1982
sewardjde4a1d02002-03-22 01:27:54 +00001983/*--------------------------------------------------------------------*/
njneb8896b2005-06-04 20:03:55 +00001984/*--- end ---*/
sewardjde4a1d02002-03-22 01:27:54 +00001985/*--------------------------------------------------------------------*/