blob: a46c6c36c26c921dcc1a534735f6941c58a67179 [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
sewardjb3a1e4b2015-08-21 11:32:26 +000010 Copyright (C) 2000-2015 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
sewardjb5f6f512005-03-10 23:59:00 +0000198/* Max number of callers for context in a suppression. */
199#define VG_MAX_SUPP_CALLERS 24
200
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);
sewardj2f340eb2011-01-28 00:44:52 +0000413 if (n_ips > VG_MAX_SUPP_CALLERS)
414 n_ips = VG_MAX_SUPP_CALLERS;
sewardj588adef2009-08-15 22:41:51 +0000415 VG_(apply_StackTrace)(printSuppForIp_nonXML,
416 text,
sewardj738856f2009-07-15 14:48:32 +0000417 VG_(get_ExeContext_StackTrace)(ec),
sewardj2f340eb2011-01-28 00:44:52 +0000418 n_ips);
sewardj738856f2009-07-15 14:48:32 +0000419
sewardj588adef2009-08-15 22:41:51 +0000420 VG_(xaprintf)(text, "}\n");
421 // zero terminate
422 VG_(xaprintf)(text, "%c", (HChar)0 );
423 // VG_(printf) of text
424
425 /* And now display it. */
426 if (! VG_(clo_xml) ) {
427
428 // the simple case
429 VG_(printf)("%s", (HChar*) VG_(indexXA)(text, 0) );
430
sewardj738856f2009-07-15 14:48:32 +0000431 } else {
sewardj588adef2009-08-15 22:41:51 +0000432
433 /* Now we have to print the XML directly. No need to go to the
434 effort of stuffing it in an XArray, since we won't need it
435 again. */
436 VG_(printf_xml)(" <suppression>\n");
437 VG_(printf_xml)(" <sname>%s</sname>\n", dummy_name);
bartb3af9cf2011-10-06 19:08:37 +0000438 VG_(printf_xml)(
439 " <skind>%pS:%pS</skind>\n", VG_(details).name, name);
florian3e81b8b2014-10-07 14:28:52 +0000440 if (num_written)
bartb3af9cf2011-10-06 19:08:37 +0000441 VG_(printf_xml)(" <skaux>%pS</skaux>\n", xtra);
sewardj588adef2009-08-15 22:41:51 +0000442
443 // Print stack trace elements
444 VG_(apply_StackTrace)(printSuppForIp_XML,
445 NULL,
446 VG_(get_ExeContext_StackTrace)(ec),
447 VG_(get_ExeContext_n_ips)(ec));
448
449 // And now the cdata bit
450 // XXX FIXME! properly handle the case where the raw text
451 // itself contains "]]>", as specified in Protocol 4.
452 VG_(printf_xml)(" <rawtext>\n");
453 VG_(printf_xml)("<![CDATA[\n");
sewardjde78f9a2009-08-15 23:33:04 +0000454 VG_(printf_xml)("%s", (HChar*) VG_(indexXA)(text, 0) );
sewardj588adef2009-08-15 22:41:51 +0000455 VG_(printf_xml)("]]>\n");
456 VG_(printf_xml)(" </rawtext>\n");
457 VG_(printf_xml)(" </suppression>\n");
458
sewardj738856f2009-07-15 14:48:32 +0000459 }
sewardj588adef2009-08-15 22:41:51 +0000460
461 VG_(deleteXA)(text);
florian3e81b8b2014-10-07 14:28:52 +0000462 VG_(free)(xtra);
sewardj738856f2009-07-15 14:48:32 +0000463}
464
465
466/* Figure out if we want to perform a given action for this error,
467 possibly by asking the user.
468*/
florian2b8059a2012-10-14 16:45:23 +0000469Bool VG_(is_action_requested) ( const HChar* action, Bool* clo )
sewardjde4a1d02002-03-22 01:27:54 +0000470{
florian19f91bb2012-11-10 22:29:54 +0000471 HChar ch, ch2;
sewardjde4a1d02002-03-22 01:27:54 +0000472 Int res;
473
sewardj738856f2009-07-15 14:48:32 +0000474 /* First off, we shouldn't be asking the user anything if
475 we're in XML mode. */
476 if (VG_(clo_xml))
477 return False; /* That's a Nein, oder Nay as they say down here in B-W */
478
njn43c799e2003-04-08 00:08:52 +0000479 if (*clo == False)
sewardjde4a1d02002-03-22 01:27:54 +0000480 return False;
481
sewardj738856f2009-07-15 14:48:32 +0000482 VG_(umsg)("\n");
sewardjde4a1d02002-03-22 01:27:54 +0000483
484 again:
485 VG_(printf)(
486 "==%d== "
njn43c799e2003-04-08 00:08:52 +0000487 "---- %s ? --- [Return/N/n/Y/y/C/c] ---- ",
488 VG_(getpid)(), action
sewardjde4a1d02002-03-22 01:27:54 +0000489 );
490
sewardj6024b212003-07-13 10:54:33 +0000491 res = VG_(read)(VG_(clo_input_fd), &ch, 1);
sewardjde4a1d02002-03-22 01:27:54 +0000492 if (res != 1) goto ioerror;
493 /* res == 1 */
494 if (ch == '\n') return False;
495 if (ch != 'N' && ch != 'n' && ch != 'Y' && ch != 'y'
496 && ch != 'C' && ch != 'c') goto again;
497
sewardj6024b212003-07-13 10:54:33 +0000498 res = VG_(read)(VG_(clo_input_fd), &ch2, 1);
sewardjde4a1d02002-03-22 01:27:54 +0000499 if (res != 1) goto ioerror;
500 if (ch2 != '\n') goto again;
501
njn43c799e2003-04-08 00:08:52 +0000502 /* No, don't want to do action. */
sewardjde4a1d02002-03-22 01:27:54 +0000503 if (ch == 'n' || ch == 'N') return False;
njn43c799e2003-04-08 00:08:52 +0000504 /* Yes, want to do action. */
sewardjde4a1d02002-03-22 01:27:54 +0000505 if (ch == 'y' || ch == 'Y') return True;
njn43c799e2003-04-08 00:08:52 +0000506 /* No, don't want to do action, and don't ask again either. */
sewardjde4a1d02002-03-22 01:27:54 +0000507 vg_assert(ch == 'c' || ch == 'C');
508
509 ioerror:
njn43c799e2003-04-08 00:08:52 +0000510 *clo = False;
sewardjde4a1d02002-03-22 01:27:54 +0000511 return False;
512}
513
514
sewardj738856f2009-07-15 14:48:32 +0000515/* Do text-mode actions on error, that is, immediately after an error
516 is printed. These are:
florianb9749a52015-07-24 11:50:12 +0000517 * possibly, call the GDB server
sewardj738856f2009-07-15 14:48:32 +0000518 * possibly, generate a suppression.
519 Note this should not be called in XML mode!
520*/
521static
florian518850b2014-10-22 22:25:30 +0000522void do_actions_on_error(const Error* err, Bool allow_db_attach)
sewardj738856f2009-07-15 14:48:32 +0000523{
524 Bool still_noisy = True;
525
sewardj3b290482011-05-06 21:02:55 +0000526 /* if user wants to debug from a certain error nr, then wait for gdb/vgdb */
527 if (VG_(clo_vgdb) != Vg_VgdbNo
528 && allow_db_attach
philippebaf69642012-02-15 22:29:30 +0000529 && VG_(dyn_vgdb_error) <= n_errs_shown) {
sewardj3b290482011-05-06 21:02:55 +0000530 VG_(umsg)("(action on error) vgdb me ... \n");
531 VG_(gdbserver)( err->tid );
532 VG_(umsg)("Continuing ...\n");
533 }
534
sewardj738856f2009-07-15 14:48:32 +0000535 /* Or maybe we want to generate the error's suppression? */
536 if (VG_(clo_gen_suppressions) == 2
537 || (VG_(clo_gen_suppressions) == 1
538 && VG_(is_action_requested)( "Print suppression", &still_noisy ))
539 ) {
540 gen_suppression(err);
541 }
542 if (VG_(clo_gen_suppressions) == 1 && !still_noisy)
543 VG_(clo_gen_suppressions) = 0;
544}
545
546
547/* Prints an error. Not entirely simple because of the differences
548 between XML and text mode output.
549
550 In XML mode:
551
552 * calls the tool's pre-show method, so the tool can create any
553 preamble ahead of the message, if it wants.
554
555 * prints the opening tag, and the <unique> and <tid> fields
556
557 * prints the tool-specific parts of the message
558
559 * if suppression generation is required, a suppression
560
561 * the closing tag
562
563 In text mode:
564
565 * calls the tool's pre-show method, so the tool can create any
566 preamble ahead of the message, if it wants.
567
568 * prints the tool-specific parts of the message
569
philipped4c37442015-03-21 16:13:08 +0000570 * calls do_actions_on_error. This optionally does a gdbserver call
571 and optionally prints a suppression; both of these may require user input.
sewardj738856f2009-07-15 14:48:32 +0000572*/
florian518850b2014-10-22 22:25:30 +0000573static void pp_Error ( const Error* err, Bool allow_db_attach, Bool xml )
sewardj738856f2009-07-15 14:48:32 +0000574{
575 /* If this fails, you probably specified your tool's method
576 dictionary incorrectly. */
577 vg_assert(VG_(needs).tool_errors);
578
sewardj3b290482011-05-06 21:02:55 +0000579 if (xml) {
sewardj738856f2009-07-15 14:48:32 +0000580
sewardj738856f2009-07-15 14:48:32 +0000581 /* Ensure that suppression generation is either completely
582 enabled or completely disabled; either way, we won't require
583 any user input. m_main.process_cmd_line_options should
584 ensure the asserted condition holds. */
585 vg_assert( VG_(clo_gen_suppressions) == 0 /* disabled */
586 || VG_(clo_gen_suppressions) == 2 /* for all errors */ );
587
588 /* Pre-show it to the tool */
589 VG_TDICT_CALL( tool_before_pp_Error, err );
590
591 /* standard preamble */
592 VG_(printf_xml)("<error>\n");
593 VG_(printf_xml)(" <unique>0x%x</unique>\n", err->unique);
floriana5e06c32015-08-05 21:16:09 +0000594 VG_(printf_xml)(" <tid>%u</tid>\n", err->tid);
florian49789512013-09-16 17:08:50 +0000595 ThreadState* tst = VG_(get_ThreadState)(err->tid);
596 if (tst->thread_name) {
597 VG_(printf_xml)(" <threadname>%s</threadname>\n", tst->thread_name);
598 }
sewardj738856f2009-07-15 14:48:32 +0000599
600 /* actually print it */
601 VG_TDICT_CALL( tool_pp_Error, err );
602
603 if (VG_(clo_gen_suppressions) > 0)
604 gen_suppression(err);
605
606 /* postamble */
607 VG_(printf_xml)("</error>\n");
njnb6267bd2009-08-12 00:14:16 +0000608 VG_(printf_xml)("\n");
sewardj738856f2009-07-15 14:48:32 +0000609
610 } else {
611
philippe7b3d3562014-11-12 19:43:29 +0000612 if (VG_(clo_error_markers)[0])
613 VG_(umsg)("%s\n", VG_(clo_error_markers)[0]);
sewardj738856f2009-07-15 14:48:32 +0000614 VG_TDICT_CALL( tool_before_pp_Error, err );
615
616 if (VG_(tdict).tool_show_ThreadIDs_for_errors
617 && err->tid > 0 && err->tid != last_tid_printed) {
florian49789512013-09-16 17:08:50 +0000618 ThreadState* tst = VG_(get_ThreadState)(err->tid);
619 if (tst->thread_name) {
floriana5e06c32015-08-05 21:16:09 +0000620 VG_(umsg)("Thread %u %s:\n", err->tid, tst->thread_name );
florian49789512013-09-16 17:08:50 +0000621 } else {
floriana5e06c32015-08-05 21:16:09 +0000622 VG_(umsg)("Thread %u:\n", err->tid );
florian49789512013-09-16 17:08:50 +0000623 }
sewardj738856f2009-07-15 14:48:32 +0000624 last_tid_printed = err->tid;
625 }
626
627 VG_TDICT_CALL( tool_pp_Error, err );
njnb6267bd2009-08-12 00:14:16 +0000628 VG_(umsg)("\n");
philippe7b3d3562014-11-12 19:43:29 +0000629 if (VG_(clo_error_markers)[1])
630 VG_(umsg)("%s\n", VG_(clo_error_markers)[1]);
sewardj738856f2009-07-15 14:48:32 +0000631
sewardj738856f2009-07-15 14:48:32 +0000632 }
philipped4c37442015-03-21 16:13:08 +0000633
634 do_actions_on_error(err, allow_db_attach);
sewardj738856f2009-07-15 14:48:32 +0000635}
636
637
sewardjb5f6f512005-03-10 23:59:00 +0000638/* Construct an error */
sewardj738856f2009-07-15 14:48:32 +0000639static
njn72718642003-07-24 08:45:32 +0000640void construct_error ( Error* err, ThreadId tid, ErrorKind ekind, Addr a,
floriane543f302012-10-21 19:43:43 +0000641 const HChar* s, void* extra, ExeContext* where )
sewardjde4a1d02002-03-22 01:27:54 +0000642{
sewardjdbada272005-07-02 21:16:30 +0000643 /* DO NOT MAKE unique_counter NON-STATIC */
644 static UInt unique_counter = 0;
645
floriane2800c92014-09-15 20:57:45 +0000646 vg_assert(tid < VG_N_THREADS);
njn72718642003-07-24 08:45:32 +0000647
njn810086f2002-11-14 12:42:47 +0000648 /* Core-only parts */
sewardjdbada272005-07-02 21:16:30 +0000649 err->unique = unique_counter++;
njn25e49d8e72002-09-23 09:36:25 +0000650 err->next = NULL;
651 err->supp = NULL;
652 err->count = 1;
njn72718642003-07-24 08:45:32 +0000653 err->tid = tid;
njn43c799e2003-04-08 00:08:52 +0000654 if (NULL == where)
sewardjadb102f2007-11-09 23:21:44 +0000655 err->where = VG_(record_ExeContext)( tid, 0 );
njn43c799e2003-04-08 00:08:52 +0000656 else
657 err->where = where;
njn1d6c4bc2002-11-21 13:38:08 +0000658
nethercote996901a2004-08-03 13:29:09 +0000659 /* Tool-relevant parts */
njn810086f2002-11-14 12:42:47 +0000660 err->ekind = ekind;
661 err->addr = a;
njn810086f2002-11-14 12:42:47 +0000662 err->extra = extra;
sewardja6022612003-07-24 23:50:17 +0000663 err->string = s;
664
njn25e49d8e72002-09-23 09:36:25 +0000665 /* sanity... */
njn72718642003-07-24 08:45:32 +0000666 vg_assert( tid < VG_N_THREADS );
njn25e49d8e72002-09-23 09:36:25 +0000667}
668
njn83f9e792005-06-11 05:04:09 +0000669
njn43c799e2003-04-08 00:08:52 +0000670
njn25e49d8e72002-09-23 09:36:25 +0000671/* Top-level entry point to the error management subsystem.
672 All detected errors are notified here; this routine decides if/when the
673 user should see the error. */
njn72718642003-07-24 08:45:32 +0000674void VG_(maybe_record_error) ( ThreadId tid,
philippec06f6842014-07-30 22:20:29 +0000675 ErrorKind ekind, Addr a,
676 const HChar* s, void* extra )
njn25e49d8e72002-09-23 09:36:25 +0000677{
njn810086f2002-11-14 12:42:47 +0000678 Error err;
679 Error* p;
680 Error* p_prev;
njn43c799e2003-04-08 00:08:52 +0000681 UInt extra_size;
njn695c16e2005-03-27 03:40:28 +0000682 VgRes exe_res = Vg_MedRes;
683 static Bool stopping_message = False;
684 static Bool slowdown_message = False;
sewardjde4a1d02002-03-22 01:27:54 +0000685
njn14319cc2005-03-13 06:26:22 +0000686 /* After M_COLLECT_NO_ERRORS_AFTER_SHOWN different errors have
687 been found, or M_COLLECT_NO_ERRORS_AFTER_FOUND total errors
sewardjf2537be2002-04-24 21:03:47 +0000688 have been found, just refuse to collect any more. This stops
689 the burden of the error-management system becoming excessive in
690 extremely buggy programs, although it does make it pretty
691 pointless to continue the Valgrind run after this point. */
sewardj2e432902002-06-13 20:44:00 +0000692 if (VG_(clo_error_limit)
njn695c16e2005-03-27 03:40:28 +0000693 && (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN
sewardj8a051722005-06-30 00:10:16 +0000694 || n_errs_found >= M_COLLECT_NO_ERRORS_AFTER_FOUND)
695 && !VG_(clo_xml)) {
sewardjde4a1d02002-03-22 01:27:54 +0000696 if (!stopping_message) {
sewardj738856f2009-07-15 14:48:32 +0000697 VG_(umsg)("\n");
sewardjf2537be2002-04-24 21:03:47 +0000698
njn695c16e2005-03-27 03:40:28 +0000699 if (n_errs_shown >= M_COLLECT_NO_ERRORS_AFTER_SHOWN) {
sewardj738856f2009-07-15 14:48:32 +0000700 VG_(umsg)(
sewardjf2537be2002-04-24 21:03:47 +0000701 "More than %d different errors detected. "
sewardj738856f2009-07-15 14:48:32 +0000702 "I'm not reporting any more.\n",
njn14319cc2005-03-13 06:26:22 +0000703 M_COLLECT_NO_ERRORS_AFTER_SHOWN );
sewardjf2537be2002-04-24 21:03:47 +0000704 } else {
sewardj738856f2009-07-15 14:48:32 +0000705 VG_(umsg)(
sewardjf2537be2002-04-24 21:03:47 +0000706 "More than %d total errors detected. "
sewardj738856f2009-07-15 14:48:32 +0000707 "I'm not reporting any more.\n",
njn14319cc2005-03-13 06:26:22 +0000708 M_COLLECT_NO_ERRORS_AFTER_FOUND );
sewardjf2537be2002-04-24 21:03:47 +0000709 }
710
sewardj738856f2009-07-15 14:48:32 +0000711 VG_(umsg)("Final error counts will be inaccurate. "
712 "Go fix your program!\n");
713 VG_(umsg)("Rerun with --error-limit=no to disable "
714 "this cutoff. Note\n");
715 VG_(umsg)("that errors may occur in your program without "
716 "prior warning from\n");
717 VG_(umsg)("Valgrind, because errors are no longer "
718 "being displayed.\n");
719 VG_(umsg)("\n");
sewardjde4a1d02002-03-22 01:27:54 +0000720 stopping_message = True;
721 }
722 return;
723 }
724
sewardjdc873c02011-07-24 16:02:33 +0000725 /* Ignore it if error acquisition is disabled for this thread. */
726 { ThreadState* tst = VG_(get_ThreadState)(tid);
727 if (tst->err_disablement_level > 0)
728 return;
729 }
730
njn14319cc2005-03-13 06:26:22 +0000731 /* After M_COLLECT_ERRORS_SLOWLY_AFTER different errors have
sewardjde4a1d02002-03-22 01:27:54 +0000732 been found, be much more conservative about collecting new
733 ones. */
sewardj8a051722005-06-30 00:10:16 +0000734 if (n_errs_shown >= M_COLLECT_ERRORS_SLOWLY_AFTER
735 && !VG_(clo_xml)) {
njn25e49d8e72002-09-23 09:36:25 +0000736 exe_res = Vg_LowRes;
sewardjde4a1d02002-03-22 01:27:54 +0000737 if (!slowdown_message) {
sewardj738856f2009-07-15 14:48:32 +0000738 VG_(umsg)("\n");
739 VG_(umsg)("More than %d errors detected. Subsequent errors\n",
740 M_COLLECT_ERRORS_SLOWLY_AFTER);
741 VG_(umsg)("will still be recorded, but in less "
742 "detail than before.\n");
sewardjde4a1d02002-03-22 01:27:54 +0000743 slowdown_message = True;
744 }
745 }
746
njn25e49d8e72002-09-23 09:36:25 +0000747 /* Build ourselves the error */
njn72718642003-07-24 08:45:32 +0000748 construct_error ( &err, tid, ekind, a, s, extra, NULL );
sewardjde4a1d02002-03-22 01:27:54 +0000749
750 /* First, see if we've got an error record matching this one. */
sewardj8a7d4e42006-10-17 01:41:17 +0000751 em_errlist_searches++;
752 p = errors;
753 p_prev = NULL;
sewardjde4a1d02002-03-22 01:27:54 +0000754 while (p != NULL) {
sewardj8a7d4e42006-10-17 01:41:17 +0000755 em_errlist_cmps++;
njn810086f2002-11-14 12:42:47 +0000756 if (eq_Error(exe_res, p, &err)) {
sewardjde4a1d02002-03-22 01:27:54 +0000757 /* Found it. */
758 p->count++;
759 if (p->supp != NULL) {
760 /* Deal correctly with suppressed errors. */
761 p->supp->count++;
nethercotef2b11482004-08-02 12:36:01 +0000762 n_errs_suppressed++;
sewardjde4a1d02002-03-22 01:27:54 +0000763 } else {
nethercotef2b11482004-08-02 12:36:01 +0000764 n_errs_found++;
sewardjde4a1d02002-03-22 01:27:54 +0000765 }
766
767 /* Move p to the front of the list so that future searches
sewardj3b290482011-05-06 21:02:55 +0000768 for it are faster. It also allows to print the last
769 error (see VG_(show_last_error). */
sewardjde4a1d02002-03-22 01:27:54 +0000770 if (p_prev != NULL) {
771 vg_assert(p_prev->next == p);
njn695c16e2005-03-27 03:40:28 +0000772 p_prev->next = p->next;
773 p->next = errors;
774 errors = p;
sewardjde4a1d02002-03-22 01:27:54 +0000775 }
sewardj7ebf7c32003-07-24 21:29:40 +0000776
sewardjde4a1d02002-03-22 01:27:54 +0000777 return;
778 }
779 p_prev = p;
780 p = p->next;
781 }
782
783 /* Didn't see it. Copy and add. */
784
njn43c799e2003-04-08 00:08:52 +0000785 /* OK, we're really going to collect it. The context is on the stack and
786 will disappear shortly, so we must copy it. First do the main
njn02bc4b82005-05-15 17:28:26 +0000787 (non-'extra') part.
njn25e49d8e72002-09-23 09:36:25 +0000788
njn02bc4b82005-05-15 17:28:26 +0000789 Then VG_(tdict).tool_update_extra can update the 'extra' part. This
njn51d827b2005-05-09 01:02:08 +0000790 is for when there are more details to fill in which take time to work
791 out but don't affect our earlier decision to include the error -- by
njn25e49d8e72002-09-23 09:36:25 +0000792 postponing those details until now, we avoid the extra work in the
njn810086f2002-11-14 12:42:47 +0000793 case where we ignore the error. Ugly.
njn43c799e2003-04-08 00:08:52 +0000794
njn02bc4b82005-05-15 17:28:26 +0000795 Then, if there is an 'extra' part, copy it too, using the size that
njn51d827b2005-05-09 01:02:08 +0000796 VG_(tdict).tool_update_extra returned. Also allow for people using
797 the void* extra field for a scalar value like an integer.
njn43c799e2003-04-08 00:08:52 +0000798 */
799
800 /* copy main part */
floriana2968cc2013-09-20 21:34:40 +0000801 p = VG_(malloc)("errormgr.mre.1", sizeof(Error));
njn25e49d8e72002-09-23 09:36:25 +0000802 *p = err;
njn43c799e2003-04-08 00:08:52 +0000803
njn02bc4b82005-05-15 17:28:26 +0000804 /* update 'extra' */
sewardjb5f6f512005-03-10 23:59:00 +0000805 switch (ekind) {
njna86f29e2006-12-14 02:55:58 +0000806 //(example code, see comment on CoreSuppKind above)
807 //case ThreadErr:
808 // vg_assert(VG_(needs).core_errors);
809 // extra_size = <something>
810 // break;
sewardjb5f6f512005-03-10 23:59:00 +0000811 default:
812 vg_assert(VG_(needs).tool_errors);
njn51d827b2005-05-09 01:02:08 +0000813 extra_size = VG_TDICT_CALL(tool_update_extra, p);
sewardjb5f6f512005-03-10 23:59:00 +0000814 break;
815 }
njn43c799e2003-04-08 00:08:52 +0000816
philippec06f6842014-07-30 22:20:29 +0000817 /* copy the error string, if there is one.
818 note: if we would have many errors with big strings, using a
819 DedupPoolAlloc for these strings will avoid duplicating
820 such string in each error using it. */
821 if (NULL != p->string) {
florian77eb20b2014-09-11 21:19:17 +0000822 p->string = VG_(strdup)("errormgr.mre.2", p->string);
philippec06f6842014-07-30 22:20:29 +0000823 }
824
njn02bc4b82005-05-15 17:28:26 +0000825 /* copy block pointed to by 'extra', if there is one */
sewardjb5f6f512005-03-10 23:59:00 +0000826 if (NULL != p->extra && 0 != extra_size) {
philippec06f6842014-07-30 22:20:29 +0000827 void* new_extra = VG_(malloc)("errormgr.mre.3", extra_size);
sewardjb5f6f512005-03-10 23:59:00 +0000828 VG_(memcpy)(new_extra, p->extra, extra_size);
829 p->extra = new_extra;
njn43c799e2003-04-08 00:08:52 +0000830 }
831
njn695c16e2005-03-27 03:40:28 +0000832 p->next = errors;
njn25e49d8e72002-09-23 09:36:25 +0000833 p->supp = is_suppressible_error(&err);
njn695c16e2005-03-27 03:40:28 +0000834 errors = p;
sewardjde4a1d02002-03-22 01:27:54 +0000835 if (p->supp == NULL) {
philippebaf69642012-02-15 22:29:30 +0000836 /* update stats */
njn606a4ae2009-08-11 00:52:40 +0000837 n_err_contexts++;
nethercotef2b11482004-08-02 12:36:01 +0000838 n_errs_found++;
philippebaf69642012-02-15 22:29:30 +0000839 n_errs_shown++;
sewardj738856f2009-07-15 14:48:32 +0000840 /* Actually show the error; more complex than you might think. */
sewardj3b290482011-05-06 21:02:55 +0000841 pp_Error( p, /*allow_db_attach*/True, VG_(clo_xml) );
sewardjde4a1d02002-03-22 01:27:54 +0000842 } else {
njn606a4ae2009-08-11 00:52:40 +0000843 n_supp_contexts++;
nethercotef2b11482004-08-02 12:36:01 +0000844 n_errs_suppressed++;
sewardjde4a1d02002-03-22 01:27:54 +0000845 p->supp->count++;
846 }
847}
848
njn43c799e2003-04-08 00:08:52 +0000849/* Second top-level entry point to the error management subsystem, for
nethercote7cc9c232004-01-21 15:08:04 +0000850 errors that the tool wants to report immediately, eg. because they're
njn43c799e2003-04-08 00:08:52 +0000851 guaranteed to only happen once. This avoids all the recording and
852 comparing stuff. But they can be suppressed; returns True if it is
njn02bc4b82005-05-15 17:28:26 +0000853 suppressed. Bool 'print_error' dictates whether to print the error.
njn18afe5d2009-08-10 08:25:39 +0000854 Bool 'count_error' dictates whether to count the error in n_errs_found.
njn47363ab2003-04-21 13:24:40 +0000855*/
floriane543f302012-10-21 19:43:43 +0000856Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind, Addr a, const HChar* s,
njn3e884182003-04-15 13:03:23 +0000857 void* extra, ExeContext* where, Bool print_error,
njn18afe5d2009-08-10 08:25:39 +0000858 Bool allow_db_attach, Bool count_error )
njn43c799e2003-04-08 00:08:52 +0000859{
njnfb289bc2007-01-12 23:59:50 +0000860 Error err;
861 Supp *su;
njn43c799e2003-04-08 00:08:52 +0000862
sewardjdc873c02011-07-24 16:02:33 +0000863 /* Ignore it if error acquisition is disabled for this thread. */
864 ThreadState* tst = VG_(get_ThreadState)(tid);
865 if (tst->err_disablement_level > 0)
866 return False; /* ignored, not suppressed */
867
njn43c799e2003-04-08 00:08:52 +0000868 /* Build ourselves the error */
njn72718642003-07-24 08:45:32 +0000869 construct_error ( &err, tid, ekind, a, s, extra, where );
njn43c799e2003-04-08 00:08:52 +0000870
871 /* Unless it's suppressed, we're going to show it. Don't need to make
872 a copy, because it's only temporary anyway.
873
njn02bc4b82005-05-15 17:28:26 +0000874 Then update the 'extra' part with VG_(tdict).tool_update_extra),
njn51d827b2005-05-09 01:02:08 +0000875 because that can have an affect on whether it's suppressed. Ignore
876 the size return value of VG_(tdict).tool_update_extra, because we're
philippec06f6842014-07-30 22:20:29 +0000877 not copying 'extra'. Similarly, 's' is also not copied. */
njn51d827b2005-05-09 01:02:08 +0000878 (void)VG_TDICT_CALL(tool_update_extra, &err);
njn43c799e2003-04-08 00:08:52 +0000879
njnfb289bc2007-01-12 23:59:50 +0000880 su = is_suppressible_error(&err);
881 if (NULL == su) {
njn606a4ae2009-08-11 00:52:40 +0000882 if (count_error) {
njn18afe5d2009-08-10 08:25:39 +0000883 n_errs_found++;
njn606a4ae2009-08-11 00:52:40 +0000884 n_err_contexts++;
885 }
njn43c799e2003-04-08 00:08:52 +0000886
887 if (print_error) {
sewardj738856f2009-07-15 14:48:32 +0000888 /* update stats */
njnfb289bc2007-01-12 23:59:50 +0000889 n_errs_shown++;
philippebaf69642012-02-15 22:29:30 +0000890 /* Actually show the error; more complex than you might think. */
891 pp_Error(&err, allow_db_attach, VG_(clo_xml));
njn43c799e2003-04-08 00:08:52 +0000892 }
njn43c799e2003-04-08 00:08:52 +0000893 return False;
894
895 } else {
njn663ab792009-08-13 04:24:38 +0000896 if (count_error) {
897 n_errs_suppressed++;
898 n_supp_contexts++;
899 }
njnfb289bc2007-01-12 23:59:50 +0000900 su->count++;
njn43c799e2003-04-08 00:08:52 +0000901 return True;
902 }
903}
904
sewardjde4a1d02002-03-22 01:27:54 +0000905
sewardjde4a1d02002-03-22 01:27:54 +0000906/*------------------------------------------------------------*/
907/*--- Exported fns ---*/
908/*------------------------------------------------------------*/
909
sewardj71bc3cb2005-05-19 00:25:45 +0000910/* Show the used suppressions. Returns False if no suppression
911 got used. */
912static Bool show_used_suppressions ( void )
913{
914 Supp *su;
915 Bool any_supp;
916
sewardj7c9e57c2005-05-24 14:21:45 +0000917 if (VG_(clo_xml))
sewardj738856f2009-07-15 14:48:32 +0000918 VG_(printf_xml)("<suppcounts>\n");
sewardj7c9e57c2005-05-24 14:21:45 +0000919
sewardj71bc3cb2005-05-19 00:25:45 +0000920 any_supp = False;
921 for (su = suppressions; su != NULL; su = su->next) {
922 if (su->count <= 0)
923 continue;
sewardj71bc3cb2005-05-19 00:25:45 +0000924 if (VG_(clo_xml)) {
bartb3af9cf2011-10-06 19:08:37 +0000925 VG_(printf_xml)( " <pair>\n"
sewardj738856f2009-07-15 14:48:32 +0000926 " <count>%d</count>\n"
bartb3af9cf2011-10-06 19:08:37 +0000927 " <name>%pS</name>\n"
sewardj738856f2009-07-15 14:48:32 +0000928 " </pair>\n",
929 su->count, su->sname );
sewardj71bc3cb2005-05-19 00:25:45 +0000930 } else {
florian3e81b8b2014-10-07 14:28:52 +0000931 HChar *xtra = NULL;
932 Int xtra_size = 0;
933 SizeT num_written;
sewardj2d9e8742009-08-07 15:46:56 +0000934 // blank line before the first shown suppression, if any
935 if (!any_supp)
936 VG_(dmsg)("\n");
florian3e81b8b2014-10-07 14:28:52 +0000937
938 do {
939 xtra_size += 256;
940 xtra = VG_(realloc)("errormgr.sus.1", xtra, xtra_size);
941 num_written = VG_TDICT_CALL(tool_print_extra_suppression_use,
942 su, xtra, xtra_size);
943 } while (num_written == xtra_size); // resize buffer and retry
944
945 // Ensure buffer is properly terminated
946 vg_assert(xtra[num_written] == '\0');
947
florian79316272014-10-07 18:36:28 +0000948 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
949 su->clo_suppressions_i);
philippe4e32d672013-10-17 22:10:41 +0000950 VG_(dmsg)("used_suppression: %6d %s %s:%d%s%s\n", su->count, su->sname,
florian79316272014-10-07 18:36:28 +0000951 filename,
philippe4e32d672013-10-17 22:10:41 +0000952 su->sname_lineno,
florian3e81b8b2014-10-07 14:28:52 +0000953 num_written ? " " : "", xtra);
954 VG_(free)(xtra);
sewardj71bc3cb2005-05-19 00:25:45 +0000955 }
sewardj2d9e8742009-08-07 15:46:56 +0000956 any_supp = True;
sewardj71bc3cb2005-05-19 00:25:45 +0000957 }
958
sewardj7c9e57c2005-05-24 14:21:45 +0000959 if (VG_(clo_xml))
sewardj738856f2009-07-15 14:48:32 +0000960 VG_(printf_xml)("</suppcounts>\n");
sewardj7c9e57c2005-05-24 14:21:45 +0000961
sewardj71bc3cb2005-05-19 00:25:45 +0000962 return any_supp;
963}
964
sewardj9f297ca2005-05-20 02:29:52 +0000965/* Show all the errors that occurred, and possibly also the
966 suppressions used. */
sewardj3b290482011-05-06 21:02:55 +0000967void VG_(show_all_errors) ( Int verbosity, Bool xml )
sewardjde4a1d02002-03-22 01:27:54 +0000968{
njn810086f2002-11-14 12:42:47 +0000969 Int i, n_min;
njn810086f2002-11-14 12:42:47 +0000970 Error *p, *p_min;
njn810086f2002-11-14 12:42:47 +0000971 Bool any_supp;
sewardjde4a1d02002-03-22 01:27:54 +0000972
sewardj3b290482011-05-06 21:02:55 +0000973 if (verbosity == 0)
sewardjde4a1d02002-03-22 01:27:54 +0000974 return;
975
njn606a4ae2009-08-11 00:52:40 +0000976 /* If we're printing XML, just show the suppressions and stop. */
sewardj3b290482011-05-06 21:02:55 +0000977 if (xml) {
sewardj71bc3cb2005-05-19 00:25:45 +0000978 (void)show_used_suppressions();
979 return;
980 }
981
982 /* We only get here if not printing XML. */
sewardj738856f2009-07-15 14:48:32 +0000983 VG_(umsg)("ERROR SUMMARY: "
floriana5e06c32015-08-05 21:16:09 +0000984 "%u errors from %u contexts (suppressed: %u from %u)\n",
sewardj738856f2009-07-15 14:48:32 +0000985 n_errs_found, n_err_contexts,
986 n_errs_suppressed, n_supp_contexts );
sewardjde4a1d02002-03-22 01:27:54 +0000987
sewardj3b290482011-05-06 21:02:55 +0000988 if (verbosity <= 1)
sewardjde4a1d02002-03-22 01:27:54 +0000989 return;
990
sewardj2d9e8742009-08-07 15:46:56 +0000991 // We do the following only at -v or above, and only in non-XML
992 // mode
993
sewardj3b290482011-05-06 21:02:55 +0000994 /* Print the contexts in order of increasing error count.
995 Once an error is shown, we add a huge value to its count to filter it
philippe362441d2013-07-22 22:00:13 +0000996 out.
997 After having shown all errors, we reset count to the original value. */
sewardjde4a1d02002-03-22 01:27:54 +0000998 for (i = 0; i < n_err_contexts; i++) {
999 n_min = (1 << 30) - 1;
1000 p_min = NULL;
njn695c16e2005-03-27 03:40:28 +00001001 for (p = errors; p != NULL; p = p->next) {
sewardjde4a1d02002-03-22 01:27:54 +00001002 if (p->supp != NULL) continue;
1003 if (p->count < n_min) {
1004 n_min = p->count;
1005 p_min = p;
1006 }
1007 }
njn663ab792009-08-13 04:24:38 +00001008 // XXX: this isn't right. See bug 203651.
floriana4ca4fe2014-09-16 09:28:12 +00001009 if (p_min == NULL) continue; //VG_(core_panic)("show_all_errors()");
sewardjde4a1d02002-03-22 01:27:54 +00001010
sewardj738856f2009-07-15 14:48:32 +00001011 VG_(umsg)("\n");
floriana5e06c32015-08-05 21:16:09 +00001012 VG_(umsg)("%d errors in context %d of %u:\n",
sewardj738856f2009-07-15 14:48:32 +00001013 p_min->count, i+1, n_err_contexts);
sewardj3b290482011-05-06 21:02:55 +00001014 pp_Error( p_min, False/*allow_db_attach*/, False /* xml */ );
sewardj738856f2009-07-15 14:48:32 +00001015
1016 // We're not printing XML -- we'd have exited above if so.
sewardj3b290482011-05-06 21:02:55 +00001017 vg_assert(! xml);
sewardjde4a1d02002-03-22 01:27:54 +00001018
1019 if ((i+1 == VG_(clo_dump_error))) {
sewardj7cf4e6b2008-05-01 20:24:26 +00001020 StackTrace ips = VG_(get_ExeContext_StackTrace)(p_min->where);
sewardjfa8ec112005-01-19 11:55:34 +00001021 VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to debugging*/,
njn394213a2005-06-19 18:38:24 +00001022 ips[0], /*debugging*/True, 0xFE/*verbosity*/,
sewardj0ec07f32006-01-12 12:32:32 +00001023 /*bbs_done*/0,
1024 /*allow redir?*/True);
sewardjde4a1d02002-03-22 01:27:54 +00001025 }
1026
sewardj3b290482011-05-06 21:02:55 +00001027 p_min->count = p_min->count + (1 << 30);
sewardjde4a1d02002-03-22 01:27:54 +00001028 }
1029
sewardj3b290482011-05-06 21:02:55 +00001030 /* reset the counts, otherwise a 2nd call does not show anything anymore */
1031 for (p = errors; p != NULL; p = p->next) {
1032 if (p->count >= (1 << 30))
1033 p->count = p->count - (1 << 30);
1034 }
1035
1036
sewardj71bc3cb2005-05-19 00:25:45 +00001037 any_supp = show_used_suppressions();
sewardjde4a1d02002-03-22 01:27:54 +00001038
sewardj2d9e8742009-08-07 15:46:56 +00001039 if (any_supp)
sewardj738856f2009-07-15 14:48:32 +00001040 VG_(umsg)("\n");
sewardj2d9e8742009-08-07 15:46:56 +00001041 // reprint this, so users don't have to scroll way up to find
1042 // the first printing
1043 VG_(umsg)("ERROR SUMMARY: "
floriana5e06c32015-08-05 21:16:09 +00001044 "%u errors from %u contexts (suppressed: %u from %u)\n",
sewardj2d9e8742009-08-07 15:46:56 +00001045 n_errs_found, n_err_contexts, n_errs_suppressed,
1046 n_supp_contexts );
sewardjde4a1d02002-03-22 01:27:54 +00001047}
1048
sewardj3b290482011-05-06 21:02:55 +00001049void VG_(show_last_error) ( void )
1050{
1051 if (n_err_contexts == 0) {
1052 VG_(umsg)("No errors yet\n");
1053 return;
1054 }
1055
1056 pp_Error( errors, False/*allow_db_attach*/, False/*xml*/ );
1057}
1058
sewardj9f297ca2005-05-20 02:29:52 +00001059
1060/* Show occurrence counts of all errors, in XML form. */
1061void VG_(show_error_counts_as_XML) ( void )
1062{
1063 Error* err;
sewardj738856f2009-07-15 14:48:32 +00001064 VG_(printf_xml)("<errorcounts>\n");
sewardj9f297ca2005-05-20 02:29:52 +00001065 for (err = errors; err != NULL; err = err->next) {
1066 if (err->supp != NULL)
1067 continue;
1068 if (err->count <= 0)
1069 continue;
sewardj738856f2009-07-15 14:48:32 +00001070 VG_(printf_xml)(" <pair>\n");
1071 VG_(printf_xml)(" <count>%d</count>\n", err->count);
1072 VG_(printf_xml)(" <unique>0x%x</unique>\n", err->unique);
1073 VG_(printf_xml)(" </pair>\n");
sewardj9f297ca2005-05-20 02:29:52 +00001074 }
sewardj738856f2009-07-15 14:48:32 +00001075 VG_(printf_xml)("</errorcounts>\n");
njnb6267bd2009-08-12 00:14:16 +00001076 VG_(printf_xml)("\n");
sewardj9f297ca2005-05-20 02:29:52 +00001077}
1078
1079
sewardjde4a1d02002-03-22 01:27:54 +00001080/*------------------------------------------------------------*/
sewardjd7a02db2008-12-12 08:07:49 +00001081/*--- Suppression parsing ---*/
sewardjde4a1d02002-03-22 01:27:54 +00001082/*------------------------------------------------------------*/
1083
sewardj8a7d4e42006-10-17 01:41:17 +00001084/* Get the next char from fd into *out_buf. Returns 1 if success,
1085 0 if eof or < 0 if error. */
1086
florian19f91bb2012-11-10 22:29:54 +00001087static Int get_char ( Int fd, HChar* out_buf )
sewardj8a7d4e42006-10-17 01:41:17 +00001088{
1089 Int r;
florian19f91bb2012-11-10 22:29:54 +00001090 static HChar buf[256];
sewardj8a7d4e42006-10-17 01:41:17 +00001091 static Int buf_size = 0;
1092 static Int buf_used = 0;
florian3130eab2014-11-14 19:25:08 +00001093 vg_assert(buf_size >= 0 && buf_size <= sizeof buf);
sewardj8a7d4e42006-10-17 01:41:17 +00001094 vg_assert(buf_used >= 0 && buf_used <= buf_size);
1095 if (buf_used == buf_size) {
florian3130eab2014-11-14 19:25:08 +00001096 r = VG_(read)(fd, buf, sizeof buf);
sewardj8a7d4e42006-10-17 01:41:17 +00001097 if (r < 0) return r; /* read failed */
florian3130eab2014-11-14 19:25:08 +00001098 vg_assert(r >= 0 && r <= sizeof buf);
sewardj8a7d4e42006-10-17 01:41:17 +00001099 buf_size = r;
1100 buf_used = 0;
1101 }
1102 if (buf_size == 0)
1103 return 0; /* eof */
florian3130eab2014-11-14 19:25:08 +00001104 vg_assert(buf_size >= 0 && buf_size <= sizeof buf);
sewardj8a7d4e42006-10-17 01:41:17 +00001105 vg_assert(buf_used >= 0 && buf_used < buf_size);
1106 *out_buf = buf[buf_used];
1107 buf_used++;
1108 return 1;
1109}
1110
philippe2193a7c2012-12-08 17:54:16 +00001111// Get a non blank non comment line.
1112// Returns True if eof.
1113static Bool get_nbnc_line ( Int fd, HChar** bufpp, SizeT* nBufp, Int* lineno )
sewardjde4a1d02002-03-22 01:27:54 +00001114{
florian19f91bb2012-11-10 22:29:54 +00001115 HChar* buf = *bufpp;
njn35db56c2009-07-24 07:38:29 +00001116 SizeT nBuf = *nBufp;
florian19f91bb2012-11-10 22:29:54 +00001117 HChar ch;
njn35db56c2009-07-24 07:38:29 +00001118 Int n, i;
philippe362441d2013-07-22 22:00:13 +00001119
1120 vg_assert(lineno); // lineno needed to correctly track line numbers.
1121
sewardjde4a1d02002-03-22 01:27:54 +00001122 while (True) {
philippe2193a7c2012-12-08 17:54:16 +00001123 buf[0] = 0;
sewardjde4a1d02002-03-22 01:27:54 +00001124 /* First, read until a non-blank char appears. */
1125 while (True) {
sewardj8a7d4e42006-10-17 01:41:17 +00001126 n = get_char(fd, &ch);
njn0c0f32a2005-03-26 04:14:01 +00001127 if (n == 1 && !VG_(isspace)(ch)) break;
florian190bd522014-09-01 21:03:54 +00001128 if (n == 1 && ch == '\n')
bart050eec52009-07-27 12:03:03 +00001129 (*lineno)++;
sewardj8a7d4e42006-10-17 01:41:17 +00001130 if (n <= 0) return True;
sewardjde4a1d02002-03-22 01:27:54 +00001131 }
1132
1133 /* Now, read the line into buf. */
1134 i = 0;
1135 buf[i++] = ch; buf[i] = 0;
1136 while (True) {
sewardj8a7d4e42006-10-17 01:41:17 +00001137 n = get_char(fd, &ch);
1138 if (n <= 0) return False; /* the next call will return True */
florian190bd522014-09-01 21:03:54 +00001139 if (ch == '\n')
bart050eec52009-07-27 12:03:03 +00001140 (*lineno)++;
sewardjde4a1d02002-03-22 01:27:54 +00001141 if (ch == '\n') break;
njn35db56c2009-07-24 07:38:29 +00001142 if (i > 0 && i == nBuf-1) {
1143 *nBufp = nBuf = nBuf * 2;
1144 #define RIDICULOUS 100000
1145 vg_assert2(nBuf < RIDICULOUS, // Just a sanity check, really.
1146 "VG_(get_line): line longer than %d chars, aborting\n",
1147 RIDICULOUS);
1148 *bufpp = buf = VG_(realloc)("errormgr.get_line.1", buf, nBuf);
1149 }
sewardjde4a1d02002-03-22 01:27:54 +00001150 buf[i++] = ch; buf[i] = 0;
1151 }
njn0c0f32a2005-03-26 04:14:01 +00001152 while (i > 1 && VG_(isspace)(buf[i-1])) {
sewardjde4a1d02002-03-22 01:27:54 +00001153 i--; buf[i] = 0;
1154 };
1155
philippe362441d2013-07-22 22:00:13 +00001156 // VG_(printf)("The line *%p %d is '%s'\n", lineno, *lineno, buf);
sewardjde4a1d02002-03-22 01:27:54 +00001157 /* Ok, we have a line. If a non-comment line, return.
1158 If a comment line, start all over again. */
1159 if (buf[0] != '#') return False;
1160 }
1161}
1162
philippe2193a7c2012-12-08 17:54:16 +00001163// True if buf starts with fun: or obj: or is ...
florian518850b2014-10-22 22:25:30 +00001164static Bool is_location_line (const HChar* buf)
philippe2193a7c2012-12-08 17:54:16 +00001165{
1166 return VG_(strncmp)(buf, "fun:", 4) == 0
1167 || VG_(strncmp)(buf, "obj:", 4) == 0
1168 || VG_(strcmp)(buf, "...") == 0;
1169}
1170
1171Bool VG_(get_line) ( Int fd, HChar** bufpp, SizeT* nBufp, Int* lineno )
1172{
1173 Bool eof = get_nbnc_line (fd, bufpp, nBufp, lineno);
1174
1175 if (eof)
1176 return True;
1177
1178 if (is_location_line(*bufpp))
1179 return True; // Not a extra suppr line
1180 else
philippe362441d2013-07-22 22:00:13 +00001181 return False; // A suppression extra line
philippe2193a7c2012-12-08 17:54:16 +00001182}
sewardjde4a1d02002-03-22 01:27:54 +00001183
philippe2c5c05e2012-07-26 21:37:36 +00001184/* True if s contains no wildcard (?, *) characters. */
florian19f91bb2012-11-10 22:29:54 +00001185static Bool is_simple_str (const HChar *s)
philippe2c5c05e2012-07-26 21:37:36 +00001186{
philippe2c5c05e2012-07-26 21:37:36 +00001187 while (*s) {
1188 if (*s == '?' || *s == '*')
1189 return False;
1190 s++;
1191 }
1192 return True;
1193}
1194
philippe7d69fd92012-02-26 21:26:00 +00001195/* buf contains the raw name of a caller, supposedly either
sewardjde4a1d02002-03-22 01:27:54 +00001196 fun:some_function_name or
philippe7d69fd92012-02-26 21:26:00 +00001197 obj:some_object_name or
1198 ...
1199 Set p->ty and p->name accordingly.
1200 p->name is allocated and set to the string
1201 after the descriptor (fun: or obj:) part.
sewardjde4a1d02002-03-22 01:27:54 +00001202 Returns False if failed.
1203*/
florian518850b2014-10-22 22:25:30 +00001204static Bool setLocationTy ( SuppLoc* p, const HChar *buf )
sewardjde4a1d02002-03-22 01:27:54 +00001205{
philippe7d69fd92012-02-26 21:26:00 +00001206 if (VG_(strncmp)(buf, "fun:", 4) == 0) {
florian77eb20b2014-09-11 21:19:17 +00001207 p->name = VG_(strdup)("errormgr.sLTy.1", buf+4);
philippe2c5c05e2012-07-26 21:37:36 +00001208 p->name_is_simple_str = is_simple_str (p->name);
sewardjb5f6f512005-03-10 23:59:00 +00001209 p->ty = FunName;
sewardjde4a1d02002-03-22 01:27:54 +00001210 return True;
1211 }
philippe7d69fd92012-02-26 21:26:00 +00001212 if (VG_(strncmp)(buf, "obj:", 4) == 0) {
florian77eb20b2014-09-11 21:19:17 +00001213 p->name = VG_(strdup)("errormgr.sLTy.2", buf+4);
philippe2c5c05e2012-07-26 21:37:36 +00001214 p->name_is_simple_str = is_simple_str (p->name);
sewardjb5f6f512005-03-10 23:59:00 +00001215 p->ty = ObjName;
sewardjde4a1d02002-03-22 01:27:54 +00001216 return True;
1217 }
philippe7d69fd92012-02-26 21:26:00 +00001218 if (VG_(strcmp)(buf, "...") == 0) {
sewardj5e519302008-11-03 23:10:25 +00001219 p->name = NULL;
philippe2c5c05e2012-07-26 21:37:36 +00001220 p->name_is_simple_str = False;
sewardj5e519302008-11-03 23:10:25 +00001221 p->ty = DotDotDot;
1222 return True;
1223 }
1224 VG_(printf)("location should be \"...\", or should start "
1225 "with \"fun:\" or \"obj:\"\n");
sewardjde4a1d02002-03-22 01:27:54 +00001226 return False;
1227}
1228
1229
nethercote7cc9c232004-01-21 15:08:04 +00001230/* Look for "tool" in a string like "tool1,tool2,tool3" */
florian518850b2014-10-22 22:25:30 +00001231static Bool tool_name_present(const HChar *name, const HChar *names)
njn11cc9252002-10-07 14:42:59 +00001232{
1233 Bool found;
florian19f91bb2012-11-10 22:29:54 +00001234 HChar *s = NULL; /* Shut gcc up */
njn11cc9252002-10-07 14:42:59 +00001235 Int len = VG_(strlen)(name);
1236
1237 found = (NULL != (s = VG_(strstr)(names, name)) &&
1238 (s == names || *(s-1) == ',') &&
1239 (*(s+len) == ',' || *(s+len) == '\0')
1240 );
1241
1242 return found;
1243}
1244
philippe362441d2013-07-22 22:00:13 +00001245/* Read suppressions from the file specified in
1246 VG_(clo_suppressions)[clo_suppressions_i]
sewardjde4a1d02002-03-22 01:27:54 +00001247 and place them in the suppressions list. If there's any difficulty
1248 doing this, just give up -- there's no point in trying to recover.
1249*/
philippe362441d2013-07-22 22:00:13 +00001250static void load_one_suppressions_file ( Int clo_suppressions_i )
sewardjde4a1d02002-03-22 01:27:54 +00001251{
florian79316272014-10-07 18:36:28 +00001252 const HChar* filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1253 clo_suppressions_i);
sewardj92645592005-07-23 09:18:34 +00001254 SysRes sres;
sewardj5e519302008-11-03 23:10:25 +00001255 Int fd, i, j, lineno = 0;
philippe2193a7c2012-12-08 17:54:16 +00001256 Bool got_a_location_line_read_by_tool;
sewardj92645592005-07-23 09:18:34 +00001257 Bool eof;
njn35db56c2009-07-24 07:38:29 +00001258 SizeT nBuf = 200;
florian19f91bb2012-11-10 22:29:54 +00001259 HChar* buf = VG_(malloc)("errormgr.losf.1", nBuf);
1260 HChar* tool_names;
1261 HChar* supp_name;
florian2b8059a2012-10-14 16:45:23 +00001262 const HChar* err_str = NULL;
sewardjb5f6f512005-03-10 23:59:00 +00001263 SuppLoc tmp_callers[VG_MAX_SUPP_CALLERS];
njnc40c3a82002-10-02 11:02:27 +00001264
njncc37d2e2009-06-24 03:49:19 +00001265 // Check it's not a directory.
1266 if (VG_(is_dir)( filename )) {
1267 if (VG_(clo_xml))
sewardj09361bf2011-01-28 00:19:25 +00001268 VG_(printf_xml)("</valgrindoutput>\n");
sewardj738856f2009-07-15 14:48:32 +00001269 VG_(umsg)("FATAL: suppressions file \"%s\" is a directory\n", filename );
njncc37d2e2009-06-24 03:49:19 +00001270 VG_(exit)(1);
1271 }
1272
1273 // Open the suppression file.
sewardj92645592005-07-23 09:18:34 +00001274 sres = VG_(open)( filename, VKI_O_RDONLY, 0 );
njncda2f0f2009-05-18 02:12:08 +00001275 if (sr_isError(sres)) {
sewardjf349d552005-11-14 17:01:01 +00001276 if (VG_(clo_xml))
sewardj09361bf2011-01-28 00:19:25 +00001277 VG_(printf_xml)("</valgrindoutput>\n");
sewardj738856f2009-07-15 14:48:32 +00001278 VG_(umsg)("FATAL: can't open suppressions file \"%s\"\n", filename );
sewardjde4a1d02002-03-22 01:27:54 +00001279 VG_(exit)(1);
1280 }
njncda2f0f2009-05-18 02:12:08 +00001281 fd = sr_Res(sres);
sewardjde4a1d02002-03-22 01:27:54 +00001282
sewardj92645592005-07-23 09:18:34 +00001283# define BOMB(S) { err_str = S; goto syntax_error; }
sewardjb5f6f512005-03-10 23:59:00 +00001284
sewardjde4a1d02002-03-22 01:27:54 +00001285 while (True) {
nethercote7cc9c232004-01-21 15:08:04 +00001286 /* Assign and initialise the two suppression halves (core and tool) */
njn810086f2002-11-14 12:42:47 +00001287 Supp* supp;
florian77eb20b2014-09-11 21:19:17 +00001288 supp = VG_(malloc)("errormgr.losf.1", sizeof(Supp));
sewardjde4a1d02002-03-22 01:27:54 +00001289 supp->count = 0;
sewardjb5f6f512005-03-10 23:59:00 +00001290
1291 // Initialise temporary reading-in buffer.
1292 for (i = 0; i < VG_MAX_SUPP_CALLERS; i++) {
1293 tmp_callers[i].ty = NoName;
philippe2c5c05e2012-07-26 21:37:36 +00001294 tmp_callers[i].name_is_simple_str = False;
sewardjb5f6f512005-03-10 23:59:00 +00001295 tmp_callers[i].name = NULL;
1296 }
1297
njn810086f2002-11-14 12:42:47 +00001298 supp->string = supp->extra = NULL;
sewardjde4a1d02002-03-22 01:27:54 +00001299
philippe2193a7c2012-12-08 17:54:16 +00001300 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
philippe7d69fd92012-02-26 21:26:00 +00001301 if (eof) {
florian77eb20b2014-09-11 21:19:17 +00001302 VG_(free)(supp);
philippe7d69fd92012-02-26 21:26:00 +00001303 break;
1304 }
sewardjde4a1d02002-03-22 01:27:54 +00001305
sewardjb5f6f512005-03-10 23:59:00 +00001306 if (!VG_STREQ(buf, "{")) BOMB("expected '{' or end-of-file");
sewardjde4a1d02002-03-22 01:27:54 +00001307
philippe2193a7c2012-12-08 17:54:16 +00001308 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
sewardjb5f6f512005-03-10 23:59:00 +00001309
1310 if (eof || VG_STREQ(buf, "}")) BOMB("unexpected '}'");
1311
florian77eb20b2014-09-11 21:19:17 +00001312 supp->sname = VG_(strdup)("errormgr.losf.2", buf);
philippe362441d2013-07-22 22:00:13 +00001313 supp->clo_suppressions_i = clo_suppressions_i;
1314 supp->sname_lineno = lineno;
sewardjde4a1d02002-03-22 01:27:54 +00001315
philippe2193a7c2012-12-08 17:54:16 +00001316 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
njn25e49d8e72002-09-23 09:36:25 +00001317
philippe2193a7c2012-12-08 17:54:16 +00001318 if (eof) BOMB("unexpected end-of-file (expecting tool:suppr)");
sewardjde4a1d02002-03-22 01:27:54 +00001319
njn94065fd2004-11-22 19:26:27 +00001320 /* Check it has the "tool1,tool2,...:supp" form (look for ':') */
njnc40c3a82002-10-02 11:02:27 +00001321 i = 0;
1322 while (True) {
1323 if (buf[i] == ':') break;
sewardjb5f6f512005-03-10 23:59:00 +00001324 if (buf[i] == '\0') BOMB("malformed 'tool1,tool2,...:supp' line");
njnc40c3a82002-10-02 11:02:27 +00001325 i++;
njn25e49d8e72002-09-23 09:36:25 +00001326 }
njnc40c3a82002-10-02 11:02:27 +00001327 buf[i] = '\0'; /* Replace ':', splitting into two strings */
1328
nethercote7cc9c232004-01-21 15:08:04 +00001329 tool_names = & buf[0];
njn11cc9252002-10-07 14:42:59 +00001330 supp_name = & buf[i+1];
njnc40c3a82002-10-02 11:02:27 +00001331
nethercote7cc9c232004-01-21 15:08:04 +00001332 if (VG_(needs).core_errors && tool_name_present("core", tool_names))
njnc40c3a82002-10-02 11:02:27 +00001333 {
sewardjb5f6f512005-03-10 23:59:00 +00001334 // A core suppression
njna86f29e2006-12-14 02:55:58 +00001335 //(example code, see comment on CoreSuppKind above)
1336 //if (VG_STREQ(supp_name, "Thread"))
1337 // supp->skind = ThreadSupp;
1338 //else
sewardjb5f6f512005-03-10 23:59:00 +00001339 BOMB("unknown core suppression type");
njnc40c3a82002-10-02 11:02:27 +00001340 }
njn95ec8702004-11-22 16:46:13 +00001341 else if (VG_(needs).tool_errors &&
nethercote7cc9c232004-01-21 15:08:04 +00001342 tool_name_present(VG_(details).name, tool_names))
njnc40c3a82002-10-02 11:02:27 +00001343 {
sewardjb5f6f512005-03-10 23:59:00 +00001344 // A tool suppression
njn51d827b2005-05-09 01:02:08 +00001345 if (VG_TDICT_CALL(tool_recognised_suppression, supp_name, supp)) {
njn810086f2002-11-14 12:42:47 +00001346 /* Do nothing, function fills in supp->skind */
sewardjb5f6f512005-03-10 23:59:00 +00001347 } else {
1348 BOMB("unknown tool suppression type");
1349 }
njnc40c3a82002-10-02 11:02:27 +00001350 }
njn25e49d8e72002-09-23 09:36:25 +00001351 else {
sewardjb5f6f512005-03-10 23:59:00 +00001352 // Ignore rest of suppression
njn25e49d8e72002-09-23 09:36:25 +00001353 while (True) {
philippe2193a7c2012-12-08 17:54:16 +00001354 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1355 if (eof) BOMB("unexpected end-of-file (when skipping suppression)");
njn43c799e2003-04-08 00:08:52 +00001356 if (VG_STREQ(buf, "}"))
njn25e49d8e72002-09-23 09:36:25 +00001357 break;
1358 }
florian77eb20b2014-09-11 21:19:17 +00001359 VG_(free)(supp->sname);
1360 VG_(free)(supp);
njn25e49d8e72002-09-23 09:36:25 +00001361 continue;
sewardjde4a1d02002-03-22 01:27:54 +00001362 }
1363
philippe2193a7c2012-12-08 17:54:16 +00001364 buf[0] = 0;
1365 // tool_read_extra_suppression_info might read lines
1366 // from fd till a location line.
njn95ec8702004-11-22 16:46:13 +00001367 if (VG_(needs).tool_errors &&
sewardjd7a02db2008-12-12 08:07:49 +00001368 !VG_TDICT_CALL(tool_read_extra_suppression_info,
philippe362441d2013-07-22 22:00:13 +00001369 fd, &buf, &nBuf, &lineno, supp))
sewardjb5f6f512005-03-10 23:59:00 +00001370 {
1371 BOMB("bad or missing extra suppression info");
sewardjde4a1d02002-03-22 01:27:54 +00001372 }
1373
philippe2193a7c2012-12-08 17:54:16 +00001374 got_a_location_line_read_by_tool = buf[0] != 0 && is_location_line(buf);
1375
sewardj5e519302008-11-03 23:10:25 +00001376 /* the main frame-descriptor reading loop */
sewardjb5f6f512005-03-10 23:59:00 +00001377 i = 0;
1378 while (True) {
philippe2193a7c2012-12-08 17:54:16 +00001379 if (got_a_location_line_read_by_tool) {
1380 got_a_location_line_read_by_tool = False;
1381 eof = False;
1382 } else {
1383 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
1384 }
sewardjb5f6f512005-03-10 23:59:00 +00001385 if (eof)
philippe2193a7c2012-12-08 17:54:16 +00001386 BOMB("unexpected end-of-file (when reading stack trace)");
sewardjb5f6f512005-03-10 23:59:00 +00001387 if (VG_STREQ(buf, "}")) {
1388 if (i > 0) {
1389 break;
1390 } else {
1391 BOMB("missing stack trace");
1392 }
1393 }
1394 if (i == VG_MAX_SUPP_CALLERS)
1395 BOMB("too many callers in stack trace");
1396 if (i > 0 && i >= VG_(clo_backtrace_size))
1397 break;
philippe7d69fd92012-02-26 21:26:00 +00001398 if (!setLocationTy(&(tmp_callers[i]), buf))
sewardj5e519302008-11-03 23:10:25 +00001399 BOMB("location should be \"...\", or should start "
1400 "with \"fun:\" or \"obj:\"");
sewardjb5f6f512005-03-10 23:59:00 +00001401 i++;
1402 }
1403
1404 // If the num callers is >= VG_(clo_backtrace_size), ignore any extra
1405 // lines and grab the '}'.
sewardj57a8f5f2003-07-06 01:40:11 +00001406 if (!VG_STREQ(buf, "}")) {
sewardjb5f6f512005-03-10 23:59:00 +00001407 do {
philippe2193a7c2012-12-08 17:54:16 +00001408 eof = get_nbnc_line ( fd, &buf, &nBuf, &lineno );
sewardjb5f6f512005-03-10 23:59:00 +00001409 } while (!eof && !VG_STREQ(buf, "}"));
1410 }
1411
sewardj5e519302008-11-03 23:10:25 +00001412 // Reject entries which are entirely composed of frame
1413 // level wildcards.
1414 vg_assert(i > 0); // guaranteed by frame-descriptor reading loop
1415 for (j = 0; j < i; j++) {
1416 if (tmp_callers[j].ty == FunName || tmp_callers[j].ty == ObjName)
1417 break;
1418 vg_assert(tmp_callers[j].ty == DotDotDot);
1419 }
1420 vg_assert(j >= 0 && j <= i);
1421 if (j == i) {
1422 // we didn't find any non-"..." entries
1423 BOMB("suppression must contain at least one location "
1424 "line which is not \"...\"");
1425 }
1426
sewardjb5f6f512005-03-10 23:59:00 +00001427 // Copy tmp_callers[] into supp->callers[]
1428 supp->n_callers = i;
florian77eb20b2014-09-11 21:19:17 +00001429 supp->callers = VG_(malloc)("errormgr.losf.4", i * sizeof(SuppLoc));
sewardjb5f6f512005-03-10 23:59:00 +00001430 for (i = 0; i < supp->n_callers; i++) {
1431 supp->callers[i] = tmp_callers[i];
sewardj57a8f5f2003-07-06 01:40:11 +00001432 }
1433
njn695c16e2005-03-27 03:40:28 +00001434 supp->next = suppressions;
1435 suppressions = supp;
sewardjde4a1d02002-03-22 01:27:54 +00001436 }
njn35db56c2009-07-24 07:38:29 +00001437 VG_(free)(buf);
sewardjde4a1d02002-03-22 01:27:54 +00001438 VG_(close)(fd);
1439 return;
1440
1441 syntax_error:
sewardjf349d552005-11-14 17:01:01 +00001442 if (VG_(clo_xml))
sewardj09361bf2011-01-28 00:19:25 +00001443 VG_(printf_xml)("</valgrindoutput>\n");
sewardj738856f2009-07-15 14:48:32 +00001444 VG_(umsg)("FATAL: in suppressions file \"%s\" near line %d:\n",
njn6f74a7e2009-03-12 00:06:45 +00001445 filename, lineno );
sewardj738856f2009-07-15 14:48:32 +00001446 VG_(umsg)(" %s\n", err_str );
sewardjb5f6f512005-03-10 23:59:00 +00001447
sewardjde4a1d02002-03-22 01:27:54 +00001448 VG_(close)(fd);
sewardj738856f2009-07-15 14:48:32 +00001449 VG_(umsg)("exiting now.\n");
nethercote8ed8a892004-11-08 13:24:25 +00001450 VG_(exit)(1);
sewardjde4a1d02002-03-22 01:27:54 +00001451
sewardjb5f6f512005-03-10 23:59:00 +00001452# undef BOMB
sewardjde4a1d02002-03-22 01:27:54 +00001453}
1454
1455
1456void VG_(load_suppressions) ( void )
1457{
1458 Int i;
njn695c16e2005-03-27 03:40:28 +00001459 suppressions = NULL;
florian79316272014-10-07 18:36:28 +00001460 for (i = 0; i < VG_(sizeXA)(VG_(clo_suppressions)); i++) {
sewardjde4a1d02002-03-22 01:27:54 +00001461 if (VG_(clo_verbosity) > 1) {
sewardj738856f2009-07-15 14:48:32 +00001462 VG_(dmsg)("Reading suppressions file: %s\n",
florian79316272014-10-07 18:36:28 +00001463 *(HChar**) VG_(indexXA)(VG_(clo_suppressions), i));
sewardjde4a1d02002-03-22 01:27:54 +00001464 }
philippe362441d2013-07-22 22:00:13 +00001465 load_one_suppressions_file( i );
sewardjde4a1d02002-03-22 01:27:54 +00001466 }
1467}
1468
sewardjd7a02db2008-12-12 08:07:49 +00001469
1470/*------------------------------------------------------------*/
1471/*--- Matching errors to suppressions ---*/
1472/*------------------------------------------------------------*/
1473
1474/* Parameterising functions for the use of VG_(generic_match) in
1475 suppression-vs-error matching. The suppression frames (SuppLoc)
1476 play the role of 'pattern'-element, and the error frames (IPs,
1477 hence simply Addrs) play the role of 'input'. In short then, we're
1478 matching a sequence of Addrs against a pattern composed of a
1479 sequence of SuppLocs.
1480*/
florian3e798632012-11-24 19:41:54 +00001481static Bool supploc_IsStar ( const void* supplocV )
sewardjd7a02db2008-12-12 08:07:49 +00001482{
florian3e798632012-11-24 19:41:54 +00001483 const SuppLoc* supploc = supplocV;
sewardjd7a02db2008-12-12 08:07:49 +00001484 return supploc->ty == DotDotDot;
1485}
1486
florian3e798632012-11-24 19:41:54 +00001487static Bool supploc_IsQuery ( const void* supplocV )
sewardjd7a02db2008-12-12 08:07:49 +00001488{
1489 return False; /* there's no '?' equivalent in the supp syntax */
1490}
1491
philippe13a59522012-08-03 23:11:39 +00001492/* IPtoFunOrObjCompleter is a lazy completer of the IPs
1493 needed to match an error with the suppression patterns.
1494 The matching between an IP and a suppression pattern is done either
1495 with the IP function name or with the IP object name.
1496 First time the fun or obj name is needed for an IP member
1497 of a stack trace, it will be computed and stored in names.
philippea0a73932014-06-15 15:42:20 +00001498 Also, if the IP corresponds to one or more inlined function calls,
1499 the inlined function names are expanded.
philippe13a59522012-08-03 23:11:39 +00001500 The IPtoFunOrObjCompleter type is designed to minimise the nr of
1501 allocations and the nr of debuginfo search. */
1502typedef
1503 struct {
1504 StackTrace ips; // stack trace we are lazily completing.
1505 UWord n_ips; // nr of elements in ips.
1506
philippea0a73932014-06-15 15:42:20 +00001507 // VG_(generic_match) calls haveInputInpC to check
1508 // for the presence of an input element identified by ixInput
1509 // (i.e. a number that identifies the ixInput element of the
1510 // input sequence). It calls supp_pattEQinp to match this input
1511 // element with a pattern.
1512 // When inlining info is used to provide inlined function calls
1513 // in stacktraces, one IP in ips can be expanded in several
1514 // function names. So, each time input (or presence of input)
1515 // is requested by VG_(generic_match), we will expand
1516 // more IP of ips till we have expanded enough to reach the
1517 // input element requested (or we cannot expand anymore).
1518
1519 UWord n_ips_expanded;
1520 // n_ips_expanded maintains the nr of elements in ips that we have
1521 // already expanded.
1522 UWord n_expanded;
1523 // n_expanded maintains the nr of elements resulting from the expansion
1524 // of the n_ips_expanded IPs. Without inlined function calls,
1525 // n_expanded == n_ips_expanded. With inlining info,
1526 // n_expanded >= n_ips_expanded.
1527
1528 Int* n_offsets_per_ip;
philippec06f6842014-07-30 22:20:29 +00001529 // n_offsets_per_ip[i] gives the nr of offsets in fun_offsets and
1530 // obj_offsets resulting of the expansion of ips[i].
philippea0a73932014-06-15 15:42:20 +00001531 // The sum of all n_expanded_per_ip must be equal to n_expanded.
philippec06f6842014-07-30 22:20:29 +00001532 // This array allows to retrieve the position in ips corresponding to
1533 // an ixInput.
philippea0a73932014-06-15 15:42:20 +00001534
1535 // size (in elements) of fun_offsets and obj_offsets.
1536 // (fun|obj)_offsets are reallocated if more space is needed
1537 // to expand an IP.
1538 UWord sz_offsets;
1539
philippe13a59522012-08-03 23:11:39 +00001540 Int* fun_offsets;
philippea0a73932014-06-15 15:42:20 +00001541 // fun_offsets[ixInput] is the offset in names where the
1542 // function name for the ixInput element of the input sequence
1543 // can be found. As one IP of ips can be expanded in several
1544 // function calls due to inlined function calls, we can have more
1545 // elements in fun_offsets than in ips.
1546 // An offset -1 means the function name has not yet been computed.
philippe13a59522012-08-03 23:11:39 +00001547 Int* obj_offsets;
philippea0a73932014-06-15 15:42:20 +00001548 // Similarly, obj_offsets[ixInput] gives the offset for the
1549 // object name for ips[ixInput]
1550 // (-1 meaning object name not yet been computed).
philippe13a59522012-08-03 23:11:39 +00001551
1552 // All function names and object names will be concatenated
1553 // in names. names is reallocated on demand.
florian19f91bb2012-11-10 22:29:54 +00001554 HChar *names;
philippe13a59522012-08-03 23:11:39 +00001555 Int names_szB; // size of names.
florian19f91bb2012-11-10 22:29:54 +00001556 Int names_free; // offset first free HChar in names.
philippe13a59522012-08-03 23:11:39 +00001557 }
1558 IPtoFunOrObjCompleter;
1559
florian518850b2014-10-22 22:25:30 +00001560static void pp_ip2fo (const IPtoFunOrObjCompleter* ip2fo)
philippe13a59522012-08-03 23:11:39 +00001561{
philippe5ab7ce82014-06-24 20:48:25 +00001562 Int i, j;
1563 Int o;
1564
1565 VG_(printf)("n_ips %lu n_ips_expanded %lu resulting in n_expanded %lu\n",
1566 ip2fo->n_ips, ip2fo->n_ips_expanded, ip2fo->n_expanded);
1567 for (i = 0; i < ip2fo->n_ips_expanded; i++) {
1568 o = 0;
1569 for (j = 0; j < i; j++)
1570 o += ip2fo->n_offsets_per_ip[j];
1571 VG_(printf)("ips %d 0x08%lx offset [%d,%d] ",
1572 i, ip2fo->ips[i],
1573 o, o+ip2fo->n_offsets_per_ip[i]-1);
1574 for (j = 0; j < ip2fo->n_offsets_per_ip[i]; j++) {
1575 VG_(printf)("%sfun:%s obj:%s\n",
1576 j == 0 ? "" : " ",
1577 ip2fo->fun_offsets[o+j] == -1 ?
1578 "<not expanded>" : &ip2fo->names[ip2fo->fun_offsets[o+j]],
1579 ip2fo->obj_offsets[o+j] == -1 ?
1580 "<not expanded>" : &ip2fo->names[ip2fo->obj_offsets[o+j]]);
1581 }
1582 }
1583}
1584
1585/* free the memory in ip2fo.
philippec06f6842014-07-30 22:20:29 +00001586 At debuglog 4, su (or NULL) will be used to show the matching
1587 (or non matching) with ip2fo. */
florian518850b2014-10-22 22:25:30 +00001588static void clearIPtoFunOrObjCompleter ( const Supp *su,
philippec06f6842014-07-30 22:20:29 +00001589 IPtoFunOrObjCompleter* ip2fo)
philippe5ab7ce82014-06-24 20:48:25 +00001590{
1591 if (DEBUG_ERRORMGR || VG_(debugLog_getLevel)() >= 4) {
florian79316272014-10-07 18:36:28 +00001592 if (su) {
1593 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1594 su->clo_suppressions_i);
philippe5ab7ce82014-06-24 20:48:25 +00001595 VG_(dmsg)("errormgr matching end suppression %s %s:%d matched:\n",
1596 su->sname,
florian79316272014-10-07 18:36:28 +00001597 filename,
philippe5ab7ce82014-06-24 20:48:25 +00001598 su->sname_lineno);
florian79316272014-10-07 18:36:28 +00001599 } else
philippe5ab7ce82014-06-24 20:48:25 +00001600 VG_(dmsg)("errormgr matching end no suppression matched:\n");
1601 VG_(pp_StackTrace) (ip2fo->ips, ip2fo->n_ips);
1602 pp_ip2fo(ip2fo);
1603 }
philippea0a73932014-06-15 15:42:20 +00001604 if (ip2fo->n_offsets_per_ip) VG_(free)(ip2fo->n_offsets_per_ip);
1605 if (ip2fo->fun_offsets) VG_(free)(ip2fo->fun_offsets);
1606 if (ip2fo->obj_offsets) VG_(free)(ip2fo->obj_offsets);
1607 if (ip2fo->names) VG_(free)(ip2fo->names);
philippe13a59522012-08-03 23:11:39 +00001608}
1609
florian46cc0452014-10-25 19:20:38 +00001610/* Grow ip2fo->names to ensure we have NEEDED characters available
philippea0a73932014-06-15 15:42:20 +00001611 in ip2fo->names and returns a pointer to the first free char. */
florian46cc0452014-10-25 19:20:38 +00001612static HChar* grow_names(IPtoFunOrObjCompleter* ip2fo, SizeT needed)
philippe13a59522012-08-03 23:11:39 +00001613{
philippea0a73932014-06-15 15:42:20 +00001614 if (ip2fo->names_szB
florian46cc0452014-10-25 19:20:38 +00001615 < ip2fo->names_free + needed) {
1616 if (needed < ERRTXT_LEN) needed = ERRTXT_LEN;
1617
philippea0a73932014-06-15 15:42:20 +00001618 ip2fo->names
1619 = VG_(realloc)("foc_names",
1620 ip2fo->names,
florian46cc0452014-10-25 19:20:38 +00001621 ip2fo->names_szB + needed);
1622 ip2fo->names_szB += needed;
philippea0a73932014-06-15 15:42:20 +00001623 }
1624 return ip2fo->names + ip2fo->names_free;
1625}
1626
1627/* foComplete returns the function name or object name for ixInput.
1628 If needFun, returns the function name for this input
1629 else returns the object name for this input.
1630 The function name or object name will be computed and added in
1631 names if not yet done. */
1632static HChar* foComplete(IPtoFunOrObjCompleter* ip2fo,
1633 Int ixInput, Bool needFun)
1634{
1635 vg_assert (ixInput < ip2fo->n_expanded);
1636 vg_assert (VG_(clo_read_inline_info) || ixInput < ip2fo->n_ips);
philippe13a59522012-08-03 23:11:39 +00001637
1638 // ptr to the offset array for function offsets (if needFun)
1639 // or object offsets (if !needFun).
1640 Int** offsets;
1641 if (needFun)
1642 offsets = &ip2fo->fun_offsets;
1643 else
1644 offsets = &ip2fo->obj_offsets;
1645
philippe13a59522012-08-03 23:11:39 +00001646 // Complete Fun name or Obj name for IP if not yet done.
philippea0a73932014-06-15 15:42:20 +00001647 if ((*offsets)[ixInput] == -1) {
florian46cc0452014-10-25 19:20:38 +00001648 const HChar* caller;
1649
philippea0a73932014-06-15 15:42:20 +00001650 (*offsets)[ixInput] = ip2fo->names_free;
philippe5ab7ce82014-06-24 20:48:25 +00001651 if (DEBUG_ERRORMGR) VG_(printf)("marking %s ixInput %d offset %d\n",
1652 needFun ? "fun" : "obj",
1653 ixInput, ip2fo->names_free);
philippe13a59522012-08-03 23:11:39 +00001654 if (needFun) {
philippea0a73932014-06-15 15:42:20 +00001655 // With inline info, fn names must have been completed already.
1656 vg_assert (!VG_(clo_read_inline_info));
philippe13a59522012-08-03 23:11:39 +00001657 /* Get the function name into 'caller_name', or "???"
1658 if unknown. */
1659 // Nb: C++-mangled names are used in suppressions. Do, though,
1660 // Z-demangle them, since otherwise it's possible to wind
1661 // up comparing "malloc" in the suppression against
1662 // "_vgrZU_libcZdsoZa_malloc" in the backtrace, and the
1663 // two of them need to be made to match.
philippea0a73932014-06-15 15:42:20 +00001664 if (!VG_(get_fnname_no_cxx_demangle)(ip2fo->ips[ixInput],
florian46cc0452014-10-25 19:20:38 +00001665 &caller,
philippea0a73932014-06-15 15:42:20 +00001666 NULL))
florian46cc0452014-10-25 19:20:38 +00001667 caller = "???";
philippe13a59522012-08-03 23:11:39 +00001668 } else {
1669 /* Get the object name into 'caller_name', or "???"
1670 if unknown. */
philippea0a73932014-06-15 15:42:20 +00001671 UWord i;
1672 UWord last_expand_pos_ips = 0;
1673 UWord pos_ips;
1674
1675 /* First get the pos in ips corresponding to ixInput */
1676 for (pos_ips = 0; pos_ips < ip2fo->n_expanded; pos_ips++) {
1677 last_expand_pos_ips += ip2fo->n_offsets_per_ip[pos_ips];
philippe5ab7ce82014-06-24 20:48:25 +00001678 if (ixInput < last_expand_pos_ips)
philippea0a73932014-06-15 15:42:20 +00001679 break;
1680 }
1681 /* pos_ips is the position in ips corresponding to ixInput.
1682 last_expand_pos_ips is the last offset in fun/obj where
1683 ips[pos_ips] has been expanded. */
1684
florian46cc0452014-10-25 19:20:38 +00001685 if (!VG_(get_objname)(ip2fo->ips[pos_ips], &caller))
1686 caller = "???";
philippea0a73932014-06-15 15:42:20 +00001687
1688 // Have all inlined calls pointing at this object name
philippe5ab7ce82014-06-24 20:48:25 +00001689 for (i = last_expand_pos_ips - ip2fo->n_offsets_per_ip[pos_ips] + 1;
1690 i < last_expand_pos_ips;
1691 i++) {
philippea0a73932014-06-15 15:42:20 +00001692 ip2fo->obj_offsets[i] = ip2fo->names_free;
philippe5ab7ce82014-06-24 20:48:25 +00001693 if (DEBUG_ERRORMGR)
philippec06f6842014-07-30 22:20:29 +00001694 VG_(printf) (" set obj_offset %lu to %d\n",
1695 i, ip2fo->names_free);
philippe5ab7ce82014-06-24 20:48:25 +00001696 }
philippe13a59522012-08-03 23:11:39 +00001697 }
florian46cc0452014-10-25 19:20:38 +00001698 SizeT caller_len = VG_(strlen)(caller);
1699 HChar* caller_name = grow_names(ip2fo, caller_len + 1);
1700 VG_(strcpy)(caller_name, caller);
1701 ip2fo->names_free += caller_len + 1;
philippe5ab7ce82014-06-24 20:48:25 +00001702 if (DEBUG_ERRORMGR) pp_ip2fo(ip2fo);
philippe13a59522012-08-03 23:11:39 +00001703 }
1704
philippea0a73932014-06-15 15:42:20 +00001705 return ip2fo->names + (*offsets)[ixInput];
1706}
1707
1708// Grow fun and obj _offsets arrays to have at least n_req elements.
1709// Ensure n_offsets_per_ip is allocated.
1710static void grow_offsets(IPtoFunOrObjCompleter* ip2fo, Int n_req)
1711{
1712 Int i;
1713
1714 // n_offsets_per_ip must always have the size of the ips array
1715 if (ip2fo->n_offsets_per_ip == NULL) {
1716 ip2fo->n_offsets_per_ip = VG_(malloc)("grow_offsets",
1717 ip2fo->n_ips * sizeof(Int));
1718 for (i = 0; i < ip2fo->n_ips; i++)
1719 ip2fo->n_offsets_per_ip[i] = 0;
1720 }
1721
1722 if (ip2fo->sz_offsets >= n_req)
1723 return;
1724
1725 // Avoid too much re-allocation by allocating at least ip2fo->n_ips
1726 // elements and at least a few more elements than the current size.
1727 if (n_req < ip2fo->n_ips)
1728 n_req = ip2fo->n_ips;
1729 if (n_req < ip2fo->sz_offsets + 5)
1730 n_req = ip2fo->sz_offsets + 5;
1731
1732 ip2fo->fun_offsets = VG_(realloc)("grow_offsets", ip2fo->fun_offsets,
1733 n_req * sizeof(Int));
1734 for (i = ip2fo->sz_offsets; i < n_req; i++)
1735 ip2fo->fun_offsets[i] = -1;
1736
1737 ip2fo->obj_offsets = VG_(realloc)("grow_offsets", ip2fo->obj_offsets,
1738 n_req * sizeof(Int));
1739 for (i = ip2fo->sz_offsets; i < n_req; i++)
1740 ip2fo->obj_offsets[i] = -1;
1741
1742 ip2fo->sz_offsets = n_req;
1743}
1744
1745// Expands more IPs from ip2fo->ips.
1746static void expandInput (IPtoFunOrObjCompleter* ip2fo, UWord ixInput )
1747{
1748 while (ip2fo->n_ips_expanded < ip2fo->n_ips
1749 && ip2fo->n_expanded <= ixInput) {
1750 if (VG_(clo_read_inline_info)) {
1751 // Expand one more IP in one or more calls.
1752 const Addr IP = ip2fo->ips[ip2fo->n_ips_expanded];
1753 InlIPCursor *iipc;
1754
1755 iipc = VG_(new_IIPC)(IP);
1756 // The only thing we really need is the nr of inlined fn calls
1757 // corresponding to the IP we will expand.
1758 // However, computing this is mostly the same as finding
1759 // the function name. So, let's directly complete the function name.
1760 do {
florian46cc0452014-10-25 19:20:38 +00001761 const HChar *caller;
philippea0a73932014-06-15 15:42:20 +00001762 grow_offsets(ip2fo, ip2fo->n_expanded+1);
1763 ip2fo->fun_offsets[ip2fo->n_expanded] = ip2fo->names_free;
1764 if (!VG_(get_fnname_no_cxx_demangle)(IP,
florian46cc0452014-10-25 19:20:38 +00001765 &caller,
philippea0a73932014-06-15 15:42:20 +00001766 iipc))
florian46cc0452014-10-25 19:20:38 +00001767 caller = "???";
1768 SizeT caller_len = VG_(strlen)(caller);
1769 HChar* caller_name = grow_names(ip2fo, caller_len + 1);
1770 VG_(strcpy)(caller_name, caller);
1771 ip2fo->names_free += caller_len + 1;
philippea0a73932014-06-15 15:42:20 +00001772 ip2fo->n_expanded++;
1773 ip2fo->n_offsets_per_ip[ip2fo->n_ips_expanded]++;
1774 } while (VG_(next_IIPC)(iipc));
1775 ip2fo->n_ips_expanded++;
1776 VG_(delete_IIPC) (iipc);
1777 } else {
1778 // Without inlined fn call info, expansion simply
1779 // consists in allocating enough elements in (fun|obj)_offsets.
1780 // The function or object names themselves will be completed
1781 // when requested.
1782 Int i;
1783 grow_offsets(ip2fo, ip2fo->n_ips);
1784 ip2fo->n_ips_expanded = ip2fo->n_ips;
1785 ip2fo->n_expanded = ip2fo->n_ips;
1786 for (i = 0; i < ip2fo->n_ips; i++)
1787 ip2fo->n_offsets_per_ip[i] = 1;
1788 }
1789 }
1790}
1791
1792static Bool haveInputInpC (void* inputCompleter, UWord ixInput )
1793{
1794 IPtoFunOrObjCompleter* ip2fo = inputCompleter;
1795 expandInput(ip2fo, ixInput);
1796 return ixInput < ip2fo->n_expanded;
philippe13a59522012-08-03 23:11:39 +00001797}
1798
florian3e798632012-11-24 19:41:54 +00001799static Bool supp_pattEQinp ( const void* supplocV, const void* addrV,
philippea0a73932014-06-15 15:42:20 +00001800 void* inputCompleter, UWord ixInput )
sewardjd7a02db2008-12-12 08:07:49 +00001801{
florian3e798632012-11-24 19:41:54 +00001802 const SuppLoc* supploc = supplocV; /* PATTERN */
florian3e798632012-11-24 19:41:54 +00001803 IPtoFunOrObjCompleter* ip2fo = inputCompleter;
florian19f91bb2012-11-10 22:29:54 +00001804 HChar* funobj_name; // Fun or Obj name.
philippe5ab7ce82014-06-24 20:48:25 +00001805 Bool ret;
sewardjd7a02db2008-12-12 08:07:49 +00001806
philippea0a73932014-06-15 15:42:20 +00001807 expandInput(ip2fo, ixInput);
1808 vg_assert(ixInput < ip2fo->n_expanded);
1809
sewardjd7a02db2008-12-12 08:07:49 +00001810 /* So, does this IP address match this suppression-line? */
1811 switch (supploc->ty) {
1812 case DotDotDot:
1813 /* supp_pattEQinp is a callback from VG_(generic_match). As
1814 per the spec thereof (see include/pub_tool_seqmatch.h), we
1815 should never get called with a pattern value for which the
1816 _IsStar or _IsQuery function would return True. Hence
1817 this can't happen. */
1818 vg_assert(0);
1819 case ObjName:
philippea0a73932014-06-15 15:42:20 +00001820 funobj_name = foComplete(ip2fo, ixInput, False /*needFun*/);
sewardjd7a02db2008-12-12 08:07:49 +00001821 break;
philippe13a59522012-08-03 23:11:39 +00001822 case FunName:
philippea0a73932014-06-15 15:42:20 +00001823 funobj_name = foComplete(ip2fo, ixInput, True /*needFun*/);
sewardjd7a02db2008-12-12 08:07:49 +00001824 break;
1825 default:
1826 vg_assert(0);
1827 }
1828
philippe13a59522012-08-03 23:11:39 +00001829 /* So now we have the function or object name in funobj_name, and
sewardjd7a02db2008-12-12 08:07:49 +00001830 the pattern (at the character level) to match against is in
1831 supploc->name. Hence (and leading to a re-entrant call of
philippe2c5c05e2012-07-26 21:37:36 +00001832 VG_(generic_match) if there is a wildcard character): */
1833 if (supploc->name_is_simple_str)
philippe5ab7ce82014-06-24 20:48:25 +00001834 ret = VG_(strcmp) (supploc->name, funobj_name) == 0;
philippe2c5c05e2012-07-26 21:37:36 +00001835 else
philippe5ab7ce82014-06-24 20:48:25 +00001836 ret = VG_(string_match)(supploc->name, funobj_name);
1837 if (DEBUG_ERRORMGR)
1838 VG_(printf) ("supp_pattEQinp %s patt %s ixUnput %lu value:%s match:%s\n",
1839 supploc->ty == FunName ? "fun" : "obj",
1840 supploc->name, ixInput, funobj_name,
1841 ret ? "yes" : "no");
1842 return ret;
sewardjd7a02db2008-12-12 08:07:49 +00001843}
1844
1845/////////////////////////////////////////////////////
1846
florian518850b2014-10-22 22:25:30 +00001847static Bool supp_matches_callers(IPtoFunOrObjCompleter* ip2fo,
1848 const Supp* su)
sewardjd7a02db2008-12-12 08:07:49 +00001849{
1850 /* Unwrap the args and set up the correct parameterisation of
1851 VG_(generic_match), using supploc_IsStar, supploc_IsQuery and
1852 supp_pattEQinp. */
philippe13a59522012-08-03 23:11:39 +00001853 /* note, StackTrace ip2fo->ips === Addr* */
sewardjd7a02db2008-12-12 08:07:49 +00001854 SuppLoc* supps = su->callers;
1855 UWord n_supps = su->n_callers;
1856 UWord szbPatt = sizeof(SuppLoc);
sewardjd7a02db2008-12-12 08:07:49 +00001857 Bool matchAll = False; /* we just want to match a prefix */
florian79316272014-10-07 18:36:28 +00001858 if (DEBUG_ERRORMGR) {
1859 HChar *filename = *(HChar**) VG_(indexXA)(VG_(clo_suppressions),
1860 su->clo_suppressions_i);
philippe5ab7ce82014-06-24 20:48:25 +00001861 VG_(dmsg)(" errormgr Checking match with %s %s:%d\n",
1862 su->sname,
florian79316272014-10-07 18:36:28 +00001863 filename,
philippe5ab7ce82014-06-24 20:48:25 +00001864 su->sname_lineno);
florian79316272014-10-07 18:36:28 +00001865 }
sewardjd7a02db2008-12-12 08:07:49 +00001866 return
1867 VG_(generic_match)(
1868 matchAll,
philippea0a73932014-06-15 15:42:20 +00001869 /*PATT*/supps, szbPatt, n_supps, 0/*initial ixPatt*/,
1870 /*INPUT*/
1871 NULL, 0, 0, /* input/szbInput/nInput 0, as using an inputCompleter */
1872 0/*initial ixInput*/,
philippe13a59522012-08-03 23:11:39 +00001873 supploc_IsStar, supploc_IsQuery, supp_pattEQinp,
philippea0a73932014-06-15 15:42:20 +00001874 ip2fo, haveInputInpC
sewardjd7a02db2008-12-12 08:07:49 +00001875 );
1876}
1877
1878/////////////////////////////////////////////////////
1879
sewardjb5f6f512005-03-10 23:59:00 +00001880static
florian518850b2014-10-22 22:25:30 +00001881Bool supp_matches_error(const Supp* su, const Error* err)
njn25e49d8e72002-09-23 09:36:25 +00001882{
njn810086f2002-11-14 12:42:47 +00001883 switch (su->skind) {
njna86f29e2006-12-14 02:55:58 +00001884 //(example code, see comment on CoreSuppKind above)
1885 //case ThreadSupp:
1886 // return (err->ekind == ThreadErr);
njn25e49d8e72002-09-23 09:36:25 +00001887 default:
njn95ec8702004-11-22 16:46:13 +00001888 if (VG_(needs).tool_errors) {
njn51d827b2005-05-09 01:02:08 +00001889 return VG_TDICT_CALL(tool_error_matches_suppression, err, su);
njn25e49d8e72002-09-23 09:36:25 +00001890 } else {
1891 VG_(printf)(
njn95ec8702004-11-22 16:46:13 +00001892 "\nUnhandled suppression type: %u. VG_(needs).tool_errors\n"
njn25e49d8e72002-09-23 09:36:25 +00001893 "probably needs to be set.\n",
floriana5e06c32015-08-05 21:16:09 +00001894 (UInt)err->ekind);
floriana4ca4fe2014-09-16 09:28:12 +00001895 VG_(core_panic)("unhandled suppression type");
njn25e49d8e72002-09-23 09:36:25 +00001896 }
1897 }
1898}
1899
sewardjd7a02db2008-12-12 08:07:49 +00001900/////////////////////////////////////////////////////
sewardj5e519302008-11-03 23:10:25 +00001901
njn810086f2002-11-14 12:42:47 +00001902/* Does an error context match a suppression? ie is this a suppressible
1903 error? If so, return a pointer to the Supp record, otherwise NULL.
njn25e49d8e72002-09-23 09:36:25 +00001904 Tries to minimise the number of symbol searches since they are expensive.
sewardjde4a1d02002-03-22 01:27:54 +00001905*/
florian518850b2014-10-22 22:25:30 +00001906static Supp* is_suppressible_error ( const Error* err )
sewardjde4a1d02002-03-22 01:27:54 +00001907{
njn810086f2002-11-14 12:42:47 +00001908 Supp* su;
sewardj8a7d4e42006-10-17 01:41:17 +00001909 Supp* su_prev;
1910
philippe13a59522012-08-03 23:11:39 +00001911 IPtoFunOrObjCompleter ip2fo;
1912 /* Conceptually, ip2fo contains an array of function names and an array of
1913 object names, corresponding to the array of IP of err->where.
1914 These names are just computed 'on demand' (so once maximum),
philippe4e32d672013-10-17 22:10:41 +00001915 then stored (efficiently, avoiding too many allocs) in ip2fo to be
1916 re-usable for the matching of the same IP with the next suppression
1917 pattern.
philippe13a59522012-08-03 23:11:39 +00001918
1919 VG_(generic_match) gets this 'IP to Fun or Obj name completer' as one
1920 of its arguments. It will then pass it to the function
1921 supp_pattEQinp which will then lazily complete the IP function name or
1922 object name inside ip2fo. Next time the fun or obj name for the same
1923 IP is needed (i.e. for the matching with the next suppr pattern), then
1924 the fun or obj name will not be searched again in the debug info. */
1925
sewardj8a7d4e42006-10-17 01:41:17 +00001926 /* stats gathering */
1927 em_supplist_searches++;
sewardjde4a1d02002-03-22 01:27:54 +00001928
philippe13a59522012-08-03 23:11:39 +00001929 /* Prepare the lazy input completer. */
1930 ip2fo.ips = VG_(get_ExeContext_StackTrace)(err->where);
1931 ip2fo.n_ips = VG_(get_ExeContext_n_ips)(err->where);
philippea0a73932014-06-15 15:42:20 +00001932 ip2fo.n_ips_expanded = 0;
1933 ip2fo.n_expanded = 0;
1934 ip2fo.sz_offsets = 0;
1935 ip2fo.n_offsets_per_ip = NULL;
philippe13a59522012-08-03 23:11:39 +00001936 ip2fo.fun_offsets = NULL;
1937 ip2fo.obj_offsets = NULL;
1938 ip2fo.names = NULL;
1939 ip2fo.names_szB = 0;
1940 ip2fo.names_free = 0;
1941
sewardjde4a1d02002-03-22 01:27:54 +00001942 /* See if the error context matches any suppression. */
philippe5ab7ce82014-06-24 20:48:25 +00001943 if (DEBUG_ERRORMGR || VG_(debugLog_getLevel)() >= 4)
1944 VG_(dmsg)("errormgr matching begin\n");
sewardj8a7d4e42006-10-17 01:41:17 +00001945 su_prev = NULL;
njn695c16e2005-03-27 03:40:28 +00001946 for (su = suppressions; su != NULL; su = su->next) {
sewardj8a7d4e42006-10-17 01:41:17 +00001947 em_supplist_cmps++;
philippe13a59522012-08-03 23:11:39 +00001948 if (supp_matches_error(su, err)
1949 && supp_matches_callers(&ip2fo, su)) {
philippe4e32d672013-10-17 22:10:41 +00001950 /* got a match. */
1951 /* Inform the tool that err is suppressed by su. */
1952 (void)VG_TDICT_CALL(tool_update_extra_suppression_use, err, su);
1953 /* Move this entry to the head of the list
sewardj8a7d4e42006-10-17 01:41:17 +00001954 in the hope of making future searches cheaper. */
1955 if (su_prev) {
1956 vg_assert(su_prev->next == su);
1957 su_prev->next = su->next;
1958 su->next = suppressions;
1959 suppressions = su;
1960 }
philippe5ab7ce82014-06-24 20:48:25 +00001961 clearIPtoFunOrObjCompleter(su, &ip2fo);
njn25e49d8e72002-09-23 09:36:25 +00001962 return su;
sewardjde4a1d02002-03-22 01:27:54 +00001963 }
sewardj8a7d4e42006-10-17 01:41:17 +00001964 su_prev = su;
sewardjde4a1d02002-03-22 01:27:54 +00001965 }
philippe5ab7ce82014-06-24 20:48:25 +00001966 clearIPtoFunOrObjCompleter(NULL, &ip2fo);
njn25e49d8e72002-09-23 09:36:25 +00001967 return NULL; /* no matches */
sewardjde4a1d02002-03-22 01:27:54 +00001968}
1969
sewardj8a7d4e42006-10-17 01:41:17 +00001970/* Show accumulated error-list and suppression-list search stats.
1971*/
1972void VG_(print_errormgr_stats) ( void )
1973{
sewardj738856f2009-07-15 14:48:32 +00001974 VG_(dmsg)(
1975 " errormgr: %'lu supplist searches, %'lu comparisons during search\n",
sewardj8a7d4e42006-10-17 01:41:17 +00001976 em_supplist_searches, em_supplist_cmps
1977 );
sewardj738856f2009-07-15 14:48:32 +00001978 VG_(dmsg)(
1979 " errormgr: %'lu errlist searches, %'lu comparisons during search\n",
sewardj8a7d4e42006-10-17 01:41:17 +00001980 em_errlist_searches, em_errlist_cmps
1981 );
1982}
1983
sewardjde4a1d02002-03-22 01:27:54 +00001984/*--------------------------------------------------------------------*/
njneb8896b2005-06-04 20:03:55 +00001985/*--- end ---*/
sewardjde4a1d02002-03-22 01:27:54 +00001986/*--------------------------------------------------------------------*/