|
From: <sv...@va...> - 2005-04-19 04:10:32
|
Author: njn
Date: 2005-04-19 05:10:25 +0100 (Tue, 19 Apr 2005)
New Revision: 3532
Added:
trunk/coregrind/errormgr.c
trunk/coregrind/pub_core_errormgr.h
trunk/include/pub_tool_errormgr.h
Removed:
trunk/coregrind/vg_errcontext.c
Modified:
trunk/coregrind/Makefile.am
trunk/coregrind/core.h
trunk/coregrind/vg_main.c
trunk/coregrind/vg_scheduler.c
trunk/coregrind/vg_signals.c
trunk/include/Makefile.am
trunk/include/tool.h.base
Log:
Renamed vg_errcontext.c as errormgr.c, and carved off the relevant parts =
of
core.h and tool.h into pub_core_errormgr.h and pub_tool_errormgr.h. All
just to improve general modularity.
Modified: trunk/coregrind/Makefile.am
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/Makefile.am 2005-04-16 14:58:34 UTC (rev 3531)
+++ trunk/coregrind/Makefile.am 2005-04-19 04:10:25 UTC (rev 3532)
@@ -27,6 +27,7 @@
noinst_HEADERS =3D \
core.h \
core_asm.h \
+ pub_core_errormgr.h \
pub_core_execontext.h \
pub_core_stacktrace.h \
ume.h \
@@ -51,6 +52,7 @@
valgrind_LDADD=3D
=20
stage2_SOURCES =3D \
+ errormgr.c \
execontext.c \
stacktrace.c \
ume.c \
@@ -58,7 +60,6 @@
vg_scheduler.c \
vg_default.c \
vg_demangle.c \
- vg_errcontext.c \
vg_hashtable.c \
vg_replace_malloc.c \
vg_main.c \
Modified: trunk/coregrind/core.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/core.h 2005-04-16 14:58:34 UTC (rev 3531)
+++ trunk/coregrind/core.h 2005-04-19 04:10:25 UTC (rev 3532)
@@ -862,26 +862,6 @@
Int debugging_verbosity );
=20
/* ---------------------------------------------------------------------
- Exports of vg_errcontext.c.
- ------------------------------------------------------------------ */
-
-typedef
- enum {=20
- ThreadErr =3D -1, // Thread error
- MutexErr =3D -2, // Mutex error
- }
- CoreErrorKind;
-
-extern void VG_(load_suppressions) ( void );
-
-extern void VG_(show_all_errors) ( void );
-
-extern Bool VG_(is_action_requested) ( Char* action, Bool* clo );
-
-extern UInt VG_(get_n_errs_found) ( void );
-
-
-/* ---------------------------------------------------------------------
Exports of vg_procselfmaps.c
------------------------------------------------------------------ */
=20
Added: trunk/coregrind/errormgr.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/errormgr.c 2005-04-16 14:58:34 UTC (rev 3531)
+++ trunk/coregrind/errormgr.c 2005-04-19 04:10:25 UTC (rev 3532)
@@ -0,0 +1,1031 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Management of error messages. errormgr.c ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2000-2005 Julian Seward=20
+ js...@ac...
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#include "core.h"
+#include "pub_core_errormgr.h"
+#include "pub_core_execontext.h"
+#include "pub_core_stacktrace.h"
+
+/*------------------------------------------------------------*/
+/*--- Globals ---*/
+/*------------------------------------------------------------*/
+
+/* After this many different unsuppressed errors have been observed,
+ be more conservative about collecting new ones. */
+#define M_COLLECT_ERRORS_SLOWLY_AFTER 50
+
+/* After this many different unsuppressed errors have been observed,
+ stop collecting errors at all, and tell the user their program is
+ evidently a steaming pile of camel dung. */
+#define M_COLLECT_NO_ERRORS_AFTER_SHOWN 300
+
+/* After this many total errors have been observed, stop collecting
+ errors at all. Counterpart to M_COLLECT_NO_ERRORS_AFTER_SHOWN. */
+#define M_COLLECT_NO_ERRORS_AFTER_FOUND 30000
+
+/* The list of error contexts found, both suppressed and unsuppressed.
+ Initially empty, and grows as errors are detected. */
+static Error* errors =3D NULL;
+
+/* The list of suppression directives, as read from the specified
+ suppressions file. */
+static Supp* suppressions =3D NULL;
+
+/* Running count of unsuppressed errors detected. */
+static UInt n_errs_found =3D 0;
+
+/* Running count of suppressed errors detected. */
+static UInt n_errs_suppressed =3D 0;
+
+/* forwards ... */
+static Supp* is_suppressible_error ( Error* err );
+
+static ThreadId last_tid_printed =3D 1;
+
+/*------------------------------------------------------------*/
+/*--- Error type ---*/
+/*------------------------------------------------------------*/
+
+/* Note: it is imperative this doesn't overlap with (0..) at all, as too=
ls
+ * effectively extend it by defining their own enums in the (0..) range.=
*/
+
+/* Errors. Extensible (via the 'extra' field). Tools can use a normal
+ enum (with element values in the normal range (0..)) for `ekind'.=20
+ Functions for getting/setting the tool-relevant fields are in
+ include/tool.h.
+
+ When errors are found and recorded with VG_(maybe_record_error)(), al=
l
+ the tool must do is pass in the four parameters; core will
+ allocate/initialise the error record.
+*/
+struct _Error {
+ struct _Error* next;
+ // NULL if unsuppressed; or ptr to suppression record.
+ Supp* supp;
+ Int count;
+ ThreadId tid;
+
+ // The tool-specific part
+ ExeContext* where; // Initialised by core
+ ErrorKind ekind; // Used by ALL. Must be in the range (0..)
+ Addr addr; // Used frequently
+ Char* string; // Used frequently
+ void* extra; // For any tool-specific extras
+};
+
+ExeContext* VG_(get_error_where) ( Error* err )
+{
+ return err->where;
+}
+
+ErrorKind VG_(get_error_kind) ( Error* err )
+{
+ return err->ekind;
+}
+
+Addr VG_(get_error_address) ( Error* err )
+{
+ return err->addr;
+}
+
+Char* VG_(get_error_string) ( Error* err )
+{
+ return err->string;
+}
+
+void* VG_(get_error_extra) ( Error* err )
+{
+ return err->extra;
+}
+
+UInt VG_(get_n_errs_found)( void )
+{
+ return n_errs_found;
+}
+
+/*------------------------------------------------------------*/
+/*--- Suppression type ---*/
+/*------------------------------------------------------------*/
+
+/* Note: it is imperative this doesn't overlap with (0..) at all, as too=
ls
+ * effectively extend it by defining their own enums in the (0..) range.=
*/
+typedef
+ enum {
+ PThreadSupp =3D -1, /* Matches PThreadErr */
+ }
+ CoreSuppKind;
+
+/* Max number of callers for context in a suppression. */
+#define VG_MAX_SUPP_CALLERS 24
+
+/* For each caller specified for a suppression, record the nature of
+ the caller name. Not of interest to tools. */
+typedef
+ enum {=20
+ NoName, /* Error case */
+ ObjName, /* Name is of an shared object file. */
+ FunName /* Name is of a function. */
+ }
+ SuppLocTy;
+
+typedef
+ struct {
+ SuppLocTy ty;
+ Char* name;
+ }
+ SuppLoc;
+
+/* Suppressions. Tools can get/set tool-relevant parts with functions
+ declared in include/tool.h. Extensible via the 'extra' field.=20
+ Tools can use a normal enum (with element values in the normal range
+ (0..)) for `skind'. */
+struct _Supp {
+ struct _Supp* next;
+ Int count; // The number of times this error has been suppressed.
+ Char* sname; // The name by which the suppression is referred to.
+
+ // Length of 'callers'
+ Int n_callers;
+ // Array of callers, for matching stack traces. First one (name of f=
n
+ // where err occurs) is mandatory; rest are optional.
+ SuppLoc* callers;
+
+ /* The tool-specific part */
+ SuppKind skind; // What kind of suppression. Must use the range (0=
..).
+ Char* string; // String -- use is optional. NULL by default.
+ void* extra; // Anything else -- use is optional. NULL by defau=
lt.
+};
+
+SuppKind VG_(get_supp_kind) ( Supp* su )
+{
+ return su->skind;
+}
+
+Char* VG_(get_supp_string) ( Supp* su )
+{
+ return su->string;
+}
+
+void* VG_(get_supp_extra) ( Supp* su )
+{
+ return su->extra;
+}
+
+
+void VG_(set_supp_kind) ( Supp* su, SuppKind skind )
+{
+ su->skind =3D skind;
+}
+
+void VG_(set_supp_string) ( Supp* su, Char* string )
+{
+ su->string =3D string;
+}
+
+void VG_(set_supp_extra) ( Supp* su, void* extra )
+{
+ su->extra =3D extra;
+}
+
+
+/*------------------------------------------------------------*/
+/*--- Helper fns ---*/
+/*------------------------------------------------------------*/
+
+/* Compare error contexts, to detect duplicates. Note that if they
+ are otherwise the same, the faulting addrs and associated rwoffsets
+ are allowed to be different. */
+static Bool eq_Error ( VgRes res, Error* e1, Error* e2 )
+{
+ if (e1->ekind !=3D e2->ekind)=20
+ return False;
+ if (!VG_(eq_ExeContext)(res, e1->where, e2->where))
+ return False;
+
+ switch (e1->ekind) {
+ // case ThreadErr:
+ // case MutexErr:
+ // vg_assert(VG_(needs).core_errors);
+ // return VG_(tm_error_equal)(res, e1, e2);
+ default:=20
+ if (VG_(needs).tool_errors)
+ return TL_(eq_Error)(res, e1, e2);
+ else {
+ VG_(printf)("\nUnhandled error type: %u. VG_(needs).tool_err=
ors\n"
+ "probably needs to be set.\n",
+ e1->ekind);
+ VG_(tool_panic)("unhandled error type");
+ }
+ }
+}
+
+static void pp_Error ( Error* err, Bool printCount )
+{
+ if (printCount)
+ VG_(message)(Vg_UserMsg, "Observed %d times:", err->count );
+ if (err->tid > 0 && err->tid !=3D last_tid_printed) {
+ VG_(message)(Vg_UserMsg, "Thread %d:", err->tid );
+ last_tid_printed =3D err->tid;
+ }
+
+ switch (err->ekind) {
+ // case ThreadErr:
+ // case MutexErr:
+ // vg_assert(VG_(needs).core_errors);
+ // VG_(tm_error_print)(err);
+ // break;
+ default:=20
+ if (VG_(needs).tool_errors)
+ TL_(pp_Error)( err );
+ else {
+ VG_(printf)("\nUnhandled error type: %u. VG_(needs).tool_er=
rors\n"
+ "probably needs to be set?\n",
+ err->ekind);
+ VG_(tool_panic)("unhandled error type");
+ }
+ }
+}
+
+/* Figure out if we want to perform a given action for this error, possi=
bly
+ by asking the user. */
+Bool VG_(is_action_requested) ( Char* action, Bool* clo )
+{
+ Char ch, ch2;
+ Int res;
+
+ if (*clo =3D=3D False)
+ return False;
+
+ VG_(message)(Vg_UserMsg, "");
+
+ again:
+ VG_(printf)(
+ "=3D=3D%d=3D=3D "
+ "---- %s ? --- [Return/N/n/Y/y/C/c] ---- ",=20
+ VG_(getpid)(), action
+ );
+
+ res =3D VG_(read)(VG_(clo_input_fd), &ch, 1);
+ if (res !=3D 1) goto ioerror;
+ /* res =3D=3D 1 */
+ if (ch =3D=3D '\n') return False;
+ if (ch !=3D 'N' && ch !=3D 'n' && ch !=3D 'Y' && ch !=3D 'y'=20
+ && ch !=3D 'C' && ch !=3D 'c') goto again;
+
+ res =3D VG_(read)(VG_(clo_input_fd), &ch2, 1);
+ if (res !=3D 1) goto ioerror;
+ if (ch2 !=3D '\n') goto again;
+
+ /* No, don't want to do action. */
+ if (ch =3D=3D 'n' || ch =3D=3D 'N') return False;
+ /* Yes, want to do action. */
+ if (ch =3D=3D 'y' || ch =3D=3D 'Y') return True;
+ /* No, don't want to do action, and don't ask again either. */
+ vg_assert(ch =3D=3D 'c' || ch =3D=3D 'C');
+
+ ioerror:
+ *clo =3D False;
+ return False;
+}
+
+
+/* Construct an error */
+static __inline__
+void construct_error ( Error* err, ThreadId tid, ErrorKind ekind, Addr a=
,
+ Char* s, void* extra, ExeContext* where )
+{
+ tl_assert(tid < VG_N_THREADS);
+
+ /* Core-only parts */
+ err->next =3D NULL;
+ err->supp =3D NULL;
+ err->count =3D 1;
+ err->tid =3D tid;
+ if (NULL =3D=3D where)
+ err->where =3D VG_(record_ExeContext)( tid );
+ else
+ err->where =3D where;
+
+ /* Tool-relevant parts */
+ err->ekind =3D ekind;
+ err->addr =3D a;
+ err->extra =3D extra;
+ err->string =3D s;
+
+ /* sanity... */
+ vg_assert( tid < VG_N_THREADS );
+}
+
+static void printSuppForIp(UInt n, Addr ip)
+{
+ static UChar buf[VG_ERRTXT_LEN];
+
+ if ( VG_(get_fnname_nodemangle) (ip, buf, VG_ERRTXT_LEN) ) {
+ VG_(printf)(" fun:%s\n", buf);
+ } else if ( VG_(get_objname)(ip, buf+7, VG_ERRTXT_LEN-7) ) {
+ VG_(printf)(" obj:%s\n", buf);
+ } else {
+ VG_(printf)(" ???:??? "
+ "# unknown, suppression will not work, sorry\n");
+ }
+}
+
+static void gen_suppression(Error* err)
+{
+ ExeContext* ec =3D VG_(get_error_where)(err);
+ Int stop_at =3D VG_(clo_backtrace_size);
+
+ /* At most VG_MAX_SUPP_CALLERS names */
+ if (stop_at > VG_MAX_SUPP_CALLERS) stop_at =3D VG_MAX_SUPP_CALLERS;
+ vg_assert(stop_at > 0);
+
+ VG_(printf)("{\n");
+ VG_(printf)(" <insert a suppression name here>\n");
+
+ if (ThreadErr =3D=3D err->ekind || MutexErr =3D=3D err->ekind) {
+ VG_(printf)(" core:PThread\n");
+
+ } else {
+ Char* name =3D TL_(get_error_name)(err);
+ if (NULL =3D=3D name) {
+ VG_(message)(Vg_UserMsg,=20
+ "(tool does not allow error to be suppressed)");
+ return;
+ }
+ VG_(printf)(" %s:%s\n", VG_(details).name, name);
+ TL_(print_extra_suppression_info)(err);
+ }
+
+ // Print stack trace elements
+ VG_(apply_StackTrace)(printSuppForIp, VG_(extract_StackTrace)(ec), st=
op_at);
+
+ VG_(printf)("}\n");
+}
+
+static=20
+void do_actions_on_error(Error* err, Bool allow_db_attach)
+{
+ Bool still_noisy =3D True;
+
+ /* Perhaps we want a debugger attach at this point? */
+ if (allow_db_attach &&
+ VG_(is_action_requested)( "Attach to debugger", & VG_(clo_db_atta=
ch) ))
+ { =20
+ VG_(printf)("starting debugger\n");
+ VG_(start_debugger)( err->tid );
+ } =20
+ /* Or maybe we want to generate the error's suppression? */
+ if (VG_(clo_gen_suppressions) =3D=3D 2
+ || (VG_(clo_gen_suppressions) =3D=3D 1
+ && VG_(is_action_requested)( "Print suppression", &still_nois=
y ))
+ ) {
+ gen_suppression(err);
+ if (VG_(clo_gen_suppressions) =3D=3D 1 && !still_noisy)
+ VG_(clo_gen_suppressions) =3D 0;
+ }
+}
+
+/* Shared between VG_(maybe_record_error)() and VG_(unique_error)(),
+ just for pretty printing purposes. */
+static Bool is_first_shown_context =3D True;
+
+/* Top-level entry point to the error management subsystem.
+ All detected errors are notified here; this routine decides if/when t=
he
+ user should see the error. */
+void VG_(maybe_record_error) ( ThreadId tid,=20
+ ErrorKind ekind, Addr a, Char* s, void* e=
xtra )
+{
+ Error err;
+ Error* p;
+ Error* p_prev;
+ UInt extra_size;
+ VgRes exe_res =3D Vg_MedRes;
+ static Bool stopping_message =3D False;
+ static Bool slowdown_message =3D False;
+ static Int n_errs_shown =3D 0;
+
+ /* After M_COLLECT_NO_ERRORS_AFTER_SHOWN different errors have
+ been found, or M_COLLECT_NO_ERRORS_AFTER_FOUND total errors
+ have been found, just refuse to collect any more. This stops
+ the burden of the error-management system becoming excessive in
+ extremely buggy programs, although it does make it pretty
+ pointless to continue the Valgrind run after this point. */
+ if (VG_(clo_error_limit)=20
+ && (n_errs_shown >=3D M_COLLECT_NO_ERRORS_AFTER_SHOWN
+ || n_errs_found >=3D M_COLLECT_NO_ERRORS_AFTER_FOUND)) {
+ if (!stopping_message) {
+ VG_(message)(Vg_UserMsg, "");
+
+ if (n_errs_shown >=3D M_COLLECT_NO_ERRORS_AFTER_SHOWN) {
+ VG_(message)(Vg_UserMsg,=20
+ "More than %d different errors detected. "
+ "I'm not reporting any more.",
+ M_COLLECT_NO_ERRORS_AFTER_SHOWN );
+ } else {
+ VG_(message)(Vg_UserMsg,=20
+ "More than %d total errors detected. "
+ "I'm not reporting any more.",
+ M_COLLECT_NO_ERRORS_AFTER_FOUND );
+ }
+
+ VG_(message)(Vg_UserMsg,=20
+ "Final error counts will be inaccurate. Go fix your program=
!");
+ VG_(message)(Vg_UserMsg,=20
+ "Rerun with --error-limit=3Dno to disable this cutoff. Note=
");
+ VG_(message)(Vg_UserMsg,=20
+ "that errors may occur in your program without prior warning=
from");
+ VG_(message)(Vg_UserMsg,=20
+ "Valgrind, because errors are no longer being displayed.");
+ VG_(message)(Vg_UserMsg, "");
+ stopping_message =3D True;
+ }
+ return;
+ }
+
+ /* After M_COLLECT_ERRORS_SLOWLY_AFTER different errors have
+ been found, be much more conservative about collecting new
+ ones. */
+ if (n_errs_shown >=3D M_COLLECT_ERRORS_SLOWLY_AFTER) {
+ exe_res =3D Vg_LowRes;
+ if (!slowdown_message) {
+ VG_(message)(Vg_UserMsg, "");
+ VG_(message)(Vg_UserMsg,=20
+ "More than %d errors detected. Subsequent errors",
+ M_COLLECT_ERRORS_SLOWLY_AFTER);
+ VG_(message)(Vg_UserMsg,=20
+ "will still be recorded, but in less detail than before.");
+ slowdown_message =3D True;
+ }
+ }
+
+ /* Build ourselves the error */
+ construct_error ( &err, tid, ekind, a, s, extra, NULL );
+
+ /* First, see if we've got an error record matching this one. */
+ p =3D errors;
+ p_prev =3D NULL;
+ while (p !=3D NULL) {
+ if (eq_Error(exe_res, p, &err)) {
+ /* Found it. */
+ p->count++;
+ if (p->supp !=3D NULL) {
+ /* Deal correctly with suppressed errors. */
+ p->supp->count++;
+ n_errs_suppressed++; =20
+ } else {
+ n_errs_found++;
+ }
+
+ /* Move p to the front of the list so that future searches
+ for it are faster. */
+ if (p_prev !=3D NULL) {
+ vg_assert(p_prev->next =3D=3D p);
+ p_prev->next =3D p->next;
+ p->next =3D errors;
+ errors =3D p;
+ }
+
+ return;
+ }
+ p_prev =3D p;
+ p =3D p->next;
+ }
+
+ /* Didn't see it. Copy and add. */
+
+ /* OK, we're really going to collect it. The context is on the stack=
and
+ will disappear shortly, so we must copy it. First do the main
+ (non-`extra') part.
+ =20
+ Then TL_(update_extra) can update the `extra' part. This is for w=
hen
+ there are more details to fill in which take time to work out but
+ don't affect our earlier decision to include the error -- by
+ postponing those details until now, we avoid the extra work in the
+ case where we ignore the error. Ugly.
+
+ Then, if there is an `extra' part, copy it too, using the size tha=
t
+ TL_(update_extra) returned. Also allow for people using the void*
+ extra field for a scalar value like an integer.
+ */
+
+ /* copy main part */
+ p =3D VG_(arena_malloc)(VG_AR_ERRORS, sizeof(Error));
+ *p =3D err;
+
+ /* update `extra' */
+ switch (ekind) {
+ // case ThreadErr:
+ // case MutexErr:
+ // vg_assert(VG_(needs).core_errors);
+ // extra_size =3D VG_(tm_error_update_extra)(p);
+ // break;
+ default:
+ vg_assert(VG_(needs).tool_errors);
+ extra_size =3D TL_(update_extra)(p);
+ break;
+ }
+
+ /* copy block pointed to by `extra', if there is one */
+ if (NULL !=3D p->extra && 0 !=3D extra_size) {=20
+ void* new_extra =3D VG_(malloc)(extra_size);
+ VG_(memcpy)(new_extra, p->extra, extra_size);
+ p->extra =3D new_extra;
+ }
+
+ p->next =3D errors;
+ p->supp =3D is_suppressible_error(&err);
+ errors =3D p;
+ if (p->supp =3D=3D NULL) {
+ n_errs_found++;
+ if (!is_first_shown_context)
+ VG_(message)(Vg_UserMsg, "");
+ pp_Error(p, False);
+ is_first_shown_context =3D False;
+ n_errs_shown++;
+ do_actions_on_error(p, /*allow_db_attach*/True);
+ } else {
+ n_errs_suppressed++;
+ p->supp->count++;
+ }
+}
+
+/* Second top-level entry point to the error management subsystem, for
+ errors that the tool wants to report immediately, eg. because they're
+ guaranteed to only happen once. This avoids all the recording and
+ comparing stuff. But they can be suppressed; returns True if it is
+ suppressed. Bool `print_error' dictates whether to print the error.=20
+ Bool `count_error' dictates whether to count the error in n_errs_foun=
d.
+*/
+Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind, Addr a, Char* s,
+ void* extra, ExeContext* where, Bool print_erro=
r,
+ Bool allow_db_attach, Bool count_error )
+{
+ Error err;
+
+ /* Build ourselves the error */
+ construct_error ( &err, tid, ekind, a, s, extra, where );
+
+ /* Unless it's suppressed, we're going to show it. Don't need to mak=
e
+ a copy, because it's only temporary anyway.
+
+ Then update the `extra' part with TL_(update_extra), because that =
can
+ have an affect on whether it's suppressed. Ignore the size return
+ value of TL_(update_extra), because we're not copying `extra'. */
+ (void)TL_(update_extra)(&err);
+
+ if (NULL =3D=3D is_suppressible_error(&err)) {
+ if (count_error)
+ n_errs_found++;
+
+ if (print_error) {
+ if (!is_first_shown_context)
+ VG_(message)(Vg_UserMsg, "");
+ pp_Error(&err, False);
+ is_first_shown_context =3D False;
+ }
+ do_actions_on_error(&err, allow_db_attach);
+
+ return False;
+
+ } else {
+ n_errs_suppressed++;
+ return True;
+ }
+}
+
+
+/*------------------------------------------------------------*/
+/*--- Exported fns ---*/
+/*------------------------------------------------------------*/
+
+/* This is called not from generated code but from the scheduler */
+void VG_(show_all_errors) ( void )
+{
+ Int i, n_min;
+ Int n_err_contexts, n_supp_contexts;
+ Error *p, *p_min;
+ Supp *su;
+ Bool any_supp;
+
+ if (VG_(clo_verbosity) =3D=3D 0)
+ return;
+
+ n_err_contexts =3D 0;
+ for (p =3D errors; p !=3D NULL; p =3D p->next) {
+ if (p->supp =3D=3D NULL)
+ n_err_contexts++;
+ }
+
+ n_supp_contexts =3D 0;
+ for (su =3D suppressions; su !=3D NULL; su =3D su->next) {
+ if (su->count > 0)
+ n_supp_contexts++;
+ }
+ VG_(message)(Vg_UserMsg,
+ "ERROR SUMMARY: "
+ "%d errors from %d contexts (suppressed: %d from %d)",
+ n_errs_found, n_err_contexts,=20
+ n_errs_suppressed, n_supp_contexts );
+
+ if (VG_(clo_verbosity) <=3D 1)
+ return;
+
+ /* Print the contexts in order of increasing error count. */
+ for (i =3D 0; i < n_err_contexts; i++) {
+ n_min =3D (1 << 30) - 1;
+ p_min =3D NULL;
+ for (p =3D errors; p !=3D NULL; p =3D p->next) {
+ if (p->supp !=3D NULL) continue;
+ if (p->count < n_min) {
+ n_min =3D p->count;
+ p_min =3D p;
+ }
+ }
+ if (p_min =3D=3D NULL) VG_(tool_panic)("show_all_errors()");
+
+ VG_(message)(Vg_UserMsg, "");
+ VG_(message)(Vg_UserMsg, "%d errors in context %d of %d:",
+ p_min->count,
+ i+1, n_err_contexts);
+ pp_Error( p_min, False );
+
+ if ((i+1 =3D=3D VG_(clo_dump_error))) {
+ StackTrace ips =3D VG_(extract_StackTrace)(p_min->where);
+ VG_(translate) ( 0 /* dummy ThreadId; irrelevant due to debuggi=
ng*/,
+ ips[0], /*debugging*/True, 0xFE/*verbosity*/);
+ }
+
+ p_min->count =3D 1 << 30;
+ }=20
+
+ if (n_supp_contexts > 0)=20
+ VG_(message)(Vg_DebugMsg, "");
+ any_supp =3D False;
+ for (su =3D suppressions; su !=3D NULL; su =3D su->next) {
+ if (su->count > 0) {
+ any_supp =3D True;
+ VG_(message)(Vg_DebugMsg, "supp: %4d %s", su->count, su->sname)=
;
+ }
+ }
+
+ if (n_err_contexts > 0) {
+ if (any_supp)=20
+ VG_(message)(Vg_UserMsg, "");
+ VG_(message)(Vg_UserMsg,
+ "IN SUMMARY: "
+ "%d errors from %d contexts (suppressed: %d from %d)"=
,
+ n_errs_found, n_err_contexts, n_errs_suppressed,
+ n_supp_contexts );
+ VG_(message)(Vg_UserMsg, "");
+ }
+}
+
+/*------------------------------------------------------------*/
+/*--- Standard suppressions ---*/
+/*------------------------------------------------------------*/
+
+/* Get a non-blank, non-comment line of at most nBuf chars from fd.
+ Skips leading spaces on the line. Return True if EOF was hit instead.=
=20
+*/
+Bool VG_(get_line) ( Int fd, Char* buf, Int nBuf )
+{
+ Char ch;
+ Int n, i;
+ while (True) {
+ /* First, read until a non-blank char appears. */
+ while (True) {
+ n =3D VG_(read)(fd, &ch, 1);
+ if (n =3D=3D 1 && !VG_(isspace)(ch)) break;
+ if (n =3D=3D 0) return True;
+ }
+
+ /* Now, read the line into buf. */
+ i =3D 0;
+ buf[i++] =3D ch; buf[i] =3D 0;
+ while (True) {
+ n =3D VG_(read)(fd, &ch, 1);
+ if (n =3D=3D 0) return False; /* the next call will return True=
*/
+ if (ch =3D=3D '\n') break;
+ if (i > 0 && i =3D=3D nBuf-1) i--;
+ buf[i++] =3D ch; buf[i] =3D 0;
+ }
+ while (i > 1 && VG_(isspace)(buf[i-1])) {=20
+ i--; buf[i] =3D 0;=20
+ };
+
+ /* VG_(printf)("The line is `%s'\n", buf); */
+ /* Ok, we have a line. If a non-comment line, return.
+ If a comment line, start all over again. */
+ if (buf[0] !=3D '#') return False;
+ }
+}
+
+
+/* *p_caller contains the raw name of a caller, supposedly either
+ fun:some_function_name or
+ obj:some_object_name.
+ Set *p_ty accordingly and advance *p_caller over the descriptor
+ (fun: or obj:) part.
+ Returns False if failed.
+*/
+static Bool setLocationTy ( SuppLoc* p )
+{
+ if (VG_(strncmp)(p->name, "fun:", 4) =3D=3D 0) {
+ p->name +=3D 4;
+ p->ty =3D FunName;
+ return True;
+ }
+ if (VG_(strncmp)(p->name, "obj:", 4) =3D=3D 0) {
+ p->name +=3D 4;
+ p->ty =3D ObjName;
+ return True;
+ }
+ VG_(printf)("location should start with fun: or obj:\n");
+ return False;
+}
+
+
+/* Look for "tool" in a string like "tool1,tool2,tool3" */
+static __inline__
+Bool tool_name_present(Char *name, Char *names)
+{
+ Bool found;
+ Char *s =3D NULL; /* Shut gcc up */
+ Int len =3D VG_(strlen)(name);
+
+ found =3D (NULL !=3D (s =3D VG_(strstr)(names, name)) &&
+ (s =3D=3D names || *(s-1) =3D=3D ',') &&
+ (*(s+len) =3D=3D ',' || *(s+len) =3D=3D '\0')
+ );
+
+ return found;
+}
+
+/* Read suppressions from the file specified in VG_(clo_suppressions)
+ and place them in the suppressions list. If there's any difficulty
+ doing this, just give up -- there's no point in trying to recover. =20
+*/
+static void load_one_suppressions_file ( Char* filename )
+{
+# define N_BUF 200
+ Int fd, i;
+ Bool eof;
+ Char buf[N_BUF+1];
+ Char* tool_names;
+ Char* supp_name;
+ Char* err_str =3D NULL;
+ SuppLoc tmp_callers[VG_MAX_SUPP_CALLERS];
+
+ fd =3D VG_(open)( filename, VKI_O_RDONLY, 0 );
+ if (fd < 0) {
+ VG_(message)(Vg_UserMsg, "FATAL: can't open suppressions file `%s'=
",=20
+ filename );
+ VG_(exit)(1);
+ }
+
+#define BOMB(S) { err_str =3D S; goto syntax_error; }
+
+ while (True) {
+ /* Assign and initialise the two suppression halves (core and tool=
) */
+ Supp* supp;
+ supp =3D VG_(arena_malloc)(VG_AR_CORE, sizeof(Supp));
+ supp->count =3D 0;
+
+ // Initialise temporary reading-in buffer.
+ for (i =3D 0; i < VG_MAX_SUPP_CALLERS; i++) {
+ tmp_callers[i].ty =3D NoName;
+ tmp_callers[i].name =3D NULL;
+ }
+
+ supp->string =3D supp->extra =3D NULL;
+
+ eof =3D VG_(get_line) ( fd, buf, N_BUF );
+ if (eof) break;
+
+ if (!VG_STREQ(buf, "{")) BOMB("expected '{' or end-of-file");
+ =20
+ eof =3D VG_(get_line) ( fd, buf, N_BUF );
+
+ if (eof || VG_STREQ(buf, "}")) BOMB("unexpected '}'");
+
+ supp->sname =3D VG_(arena_strdup)(VG_AR_CORE, buf);
+
+ eof =3D VG_(get_line) ( fd, buf, N_BUF );
+
+ if (eof) BOMB("unexpected end-of-file");
+
+ /* Check it has the "tool1,tool2,...:supp" form (look for ':') */
+ i =3D 0;
+ while (True) {
+ if (buf[i] =3D=3D ':') break;
+ if (buf[i] =3D=3D '\0') BOMB("malformed 'tool1,tool2,...:supp' =
line");
+ i++;
+ }
+ buf[i] =3D '\0'; /* Replace ':', splitting into two strings =
*/
+
+ tool_names =3D & buf[0];
+ supp_name =3D & buf[i+1];
+
+ if (VG_(needs).core_errors && tool_name_present("core", tool_names=
))
+ {
+ // A core suppression
+ if (VG_STREQ(supp_name, "PThread"))
+ supp->skind =3D PThreadSupp;
+ else
+ BOMB("unknown core suppression type");
+ }
+ else if (VG_(needs).tool_errors &&=20
+ tool_name_present(VG_(details).name, tool_names))
+ {
+ // A tool suppression
+ if (TL_(recognised_suppression)(supp_name, supp)) {
+ /* Do nothing, function fills in supp->skind */
+ } else {
+ BOMB("unknown tool suppression type");
+ }
+ }
+ else {
+ // Ignore rest of suppression
+ while (True) {
+ eof =3D VG_(get_line) ( fd, buf, N_BUF );
+ if (eof) BOMB("unexpected end-of-file");
+ if (VG_STREQ(buf, "}"))
+ break;
+ }
+ continue;
+ }
+
+ if (VG_(needs).tool_errors &&=20
+ !TL_(read_extra_suppression_info)(fd, buf, N_BUF, supp))
+ {
+ BOMB("bad or missing extra suppression info");
+ }
+
+ i =3D 0;
+ while (True) {
+ eof =3D VG_(get_line) ( fd, buf, N_BUF );
+ if (eof)
+ BOMB("unexpected end-of-file");
+ if (VG_STREQ(buf, "}")) {
+ if (i > 0) {
+ break;
+ } else {
+ BOMB("missing stack trace");
+ }
+ }
+ if (i =3D=3D VG_MAX_SUPP_CALLERS)
+ BOMB("too many callers in stack trace");
+ if (i > 0 && i >=3D VG_(clo_backtrace_size))=20
+ break;
+ tmp_callers[i].name =3D VG_(arena_strdup)(VG_AR_CORE, buf);
+ if (!setLocationTy(&(tmp_callers[i])))
+ BOMB("location should start with 'fun:' or 'obj:'");
+ i++;
+ }
+
+ // If the num callers is >=3D VG_(clo_backtrace_size), ignore any =
extra
+ // lines and grab the '}'.
+ if (!VG_STREQ(buf, "}")) {
+ do {
+ eof =3D VG_(get_line) ( fd, buf, N_BUF );
+ } while (!eof && !VG_STREQ(buf, "}"));
+ }
+
+ // Copy tmp_callers[] into supp->callers[]
+ supp->n_callers =3D i;
+ supp->callers =3D VG_(arena_malloc)(VG_AR_CORE, i*sizeof(SuppLoc))=
;
+ for (i =3D 0; i < supp->n_callers; i++) {
+ supp->callers[i] =3D tmp_callers[i];
+ }
+
+ supp->next =3D suppressions;
+ suppressions =3D supp;
+ }
+ VG_(close)(fd);
+ return;
+
+ syntax_error:
+ VG_(message)(Vg_UserMsg,=20
+ "FATAL: in suppressions file `%s': %s", filename, err_st=
r );
+ =20
+ VG_(close)(fd);
+ VG_(message)(Vg_UserMsg, "exiting now.");
+ VG_(exit)(1);
+
+# undef BOMB
+# undef N_BUF =20
+}
+
+
+void VG_(load_suppressions) ( void )
+{
+ Int i;
+ suppressions =3D NULL;
+ for (i =3D 0; i < VG_(clo_n_suppressions); i++) {
+ if (VG_(clo_verbosity) > 1) {
+ VG_(message)(Vg_DebugMsg, "Reading suppressions file: %s",=20
+ VG_(clo_suppressions)[i] );
+ }
+ load_one_suppressions_file( VG_(clo_suppressions)[i] );
+ }
+}
+
+static
+Bool supp_matches_error(Supp* su, Error* err)
+{
+ switch (su->skind) {
+ case PThreadSupp:
+ return (err->ekind =3D=3D ThreadErr || err->ekind =3D=3D MutexE=
rr);
+ default:
+ if (VG_(needs).tool_errors) {
+ return TL_(error_matches_suppression)(err, su);
+ } else {
+ VG_(printf)(
+ "\nUnhandled suppression type: %u. VG_(needs).tool_error=
s\n"
+ "probably needs to be set.\n",
+ err->ekind);
+ VG_(tool_panic)("unhandled suppression type");
+ }
+ }
+}
+
+static
+Bool supp_matches_callers(Error* err, Supp* su)
+{
+ Int i;
+ Char caller_name[VG_ERRTXT_LEN];
+ StackTrace ips =3D VG_(extract_StackTrace)(err->where);
+
+ for (i =3D 0; i < su->n_callers; i++) {
+ Addr a =3D ips[i];
+ vg_assert(su->callers[i].name !=3D NULL);
+ switch (su->callers[i].ty) {
+ case ObjName:=20
+ if (!VG_(get_objname)(a, caller_name, VG_ERRTXT_LEN))
+ return False;
+ break;=20
+
+ case FunName:=20
+ // Nb: mangled names used in suppressions
+ if (!VG_(get_fnname_nodemangle)(a, caller_name, VG_ERRTXT_LE=
N))
+ return False;
+ break;
+ default: VG_(tool_panic)("supp_matches_callers");
+ }
+ if (!VG_(string_match)(su->callers[i].name, caller_name))
+ return False;
+ }
+
+ /* If we reach here, it's a match */
+ return True;
+}
+
+/* Does an error context match a suppression? ie is this a suppressible
+ error? If so, return a pointer to the Supp record, otherwise NULL.
+ Tries to minimise the number of symbol searches since they are expens=
ive. =20
+*/
+static Supp* is_suppressible_error ( Error* err )
+{
+ Supp* su;
+
+ /* See if the error context matches any suppression. */
+ for (su =3D suppressions; su !=3D NULL; su =3D su->next) {
+ if (supp_matches_error(su, err) &&
+ supp_matches_callers(err, su))
+ {
+ return su;
+ }
+ }
+ return NULL; /* no matches */
+}
+
+/*--------------------------------------------------------------------*/
+/*--- end ---*/
+/*--------------------------------------------------------------------*/
Added: trunk/coregrind/pub_core_errormgr.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/pub_core_errormgr.h 2005-04-16 14:58:34 UTC (rev 3531=
)
+++ trunk/coregrind/pub_core_errormgr.h 2005-04-19 04:10:25 UTC (rev 3532=
)
@@ -0,0 +1,64 @@
+/*--------------------------------------------------------------------*/
+/*--- ErrorMgr: management of errors and suppressions. ---*/
+/*--- pub_core_errormgr.h ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+ This file is part of Valgrind, a dynamic binary instrumentation
+ framework.
+
+ Copyright (C) 2000-2005 Julian Seward
+ js...@ac...
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ The GNU General Public License is contained in the file COPYING.
+*/
+
+#ifndef __PUB_CORE_ERRORMGR_H
+#define __PUB_CORE_ERRORMGR_H
+
+//--------------------------------------------------------------------
+// PURPOSE: This module manages errors recording and printing,=20
+// which includes suppression reading and writing.
+//--------------------------------------------------------------------
+
+#include "pub_tool_errormgr.h"
+
+//#include "pub_core_stacktrace.h"
+
+// XXX: should this be in pthreadmodel.c?
+// These must be negative, so as to not overlap with tool error kinds.
+typedef
+ enum {=20
+ ThreadErr =3D -1, // Thread error
+ MutexErr =3D -2, // Mutex error
+ }
+ CoreErrorKind;
+
+extern void VG_(load_suppressions) ( void );
+
+extern void VG_(show_all_errors) ( void );
+
+extern Bool VG_(is_action_requested) ( Char* action, Bool* clo );
+
+extern UInt VG_(get_n_errs_found) ( void );
+
+#endif // __PUB_CORE_ERRORMGR_H
+
+/*--------------------------------------------------------------------*/
+/*--- end ---*/
+/*--------------------------------------------------------------------*/
Deleted: trunk/coregrind/vg_errcontext.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- trunk/coregrind/vg_errcontext.c 2005-04-16 14:58:34 UTC (rev 3531)
+++ trunk/coregrind/vg_errcontext.c 2005-04-19 04:10:25 UTC (rev 3532)
@@ -1,1030 +0,0 @@
-
-/*--------------------------------------------------------------------*/
-/*--- Management of error messages. vg_errcontext.c ---*/
-/*--------------------------------------------------------------------*/
-
-/*
- This file is part of Valgrind, a dynamic binary instrumentation
- framework.
-
- Copyright (C) 2000-2005 Julian Seward=20
- js...@ac...
-
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2 of the
- License, or (at your option) any later version.
-
- This program is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307, USA.
-
- The GNU General Public License is contained in the file COPYING.
-*/
-
-#include "core.h"
-#include "pub_core_execontext.h"
-
-/*------------------------------------------------------------*/
-/*--- Globals ---*/
-/*------------------------------------------------------------*/
-
-/* After this many different unsuppressed errors have been observed,
- be more conservative about collecting new ones. */
-#define M_COLLECT_ERRORS_SLOWLY_AFTER 50
-
-/* After this many different unsuppressed errors have been observed,
- stop collecting errors at all, and tell the user their program is
- evidently a steaming pile of camel dung. */
-#define M_COLLECT_NO_ERRORS_AFTER_SHOWN 300
-
-/* After this many total errors have been observed, stop collecting
- errors at all. Counterpart to M_COLLECT_NO_ERRORS_AFTER_SHOWN. */
-#define M_COLLECT_NO_ERRORS_AFTER_FOUND 30000
-
-/* The list of error contexts found, both suppressed and unsuppressed.
- Initially empty, and grows as errors are detected. */
-static Error* errors =3D NULL;
-
-/* The list of suppression directives, as read from the specified
- suppressions file. */
-static Supp* suppressions =3D NULL;
-
-/* Running count of unsuppressed errors detected. */
-static UInt n_errs_found =3D 0;
-
-/* Running count of suppressed errors detected. */
-static UInt n_errs_suppressed =3D 0;
-
-/* forwards ... */
-static Supp* is_suppressible_error ( Error* err );
-
-static ThreadId last_tid_printed =3D 1;
-
-/*------------------------------------------------------------*/
-/*--- Error type ---*/
-/*------------------------------------------------------------*/
-
-/* Note: it is imperative this doesn't overlap with (0..) at all, as too=
ls
- * effectively extend it by defining their own enums in the (0..) range.=
*/
-
-/* Errors. Extensible (via the 'extra' field). Tools can use a normal
- enum (with element values in the normal range (0..)) for `ekind'.=20
- Functions for getting/setting the tool-relevant fields are in
- include/tool.h.
-
- When errors are found and recorded with VG_(maybe_record_error)(), al=
l
- the tool must do is pass in the four parameters; core will
- allocate/initialise the error record.
-*/
-struct _Error {
- struct _Error* next;
- // NULL if unsuppressed; or ptr to suppression record.
- Supp* supp;
- Int count;
- ThreadId tid;
-
- // The tool-specific part
- ExeContext* where; // Initialised by core
- Int ekind; // Used by ALL. Must be in the range (0..)
- Addr addr; // Used frequently
- Char* string; // Used frequently
- void* extra; // For any tool-specific extras
-};
-
-ExeContext* VG_(get_error_where) ( Error* err )
-{
- return err->where;
-}
-
-ErrorKind VG_(get_error_kind) ( Error* err )
-{
- return err->ekind;
-}
-
-Addr VG_(get_error_address) ( Error* err )
-{
- return err->addr;
-}
-
-Char* VG_(get_error_string) ( Error* err )
-{
- return err->string;
-}
-
-void* VG_(get_error_extra) ( Error* err )
-{
- return err->extra;
-}
-
-UInt VG_(get_n_errs_found)( void )
-{
- return n_errs_found;
-}
-
-/*------------------------------------------------------------*/
-/*--- Suppression type ---*/
-/*------------------------------------------------------------*/
-
-/* Note: it is imperative this doesn't overlap with (0..) at all, as too=
ls
- * effectively extend it by defining their own enums in the (0..) range.=
*/
-typedef
- enum {
- PThreadSupp =3D -1, /* Matches PThreadErr */
- }
- CoreSuppKind;
-
-/* Max number of callers for context in a suppression. */
-#define VG_MAX_SUPP_CALLERS 24
-
-/* For each caller specified for a suppression, record the nature of
- the caller name. Not of interest to tools. */
-typedef
- enum {=20
- NoName, /* Error case */
- ObjName, /* Name is of an shared object file. */
- FunName /* Name is of a function. */
- }
- SuppLocTy;
-
-typedef
- struct {
- SuppLocTy ty;
- Char* name;
- }
- SuppLoc;
-
-/* Suppressions. Tools can get/set tool-relevant parts with functions
- declared in include/tool.h. Extensible via the 'extra' field.=20
- Tools can use a normal enum (with element values in the normal range
- (0..)) for `skind'. */
-struct _Supp {
- struct _Supp* next;
- Int count; // The number of times this error has been suppressed.
- Char* sname; // The name by which the suppression is referred to.
-
- // Length of 'callers'
- Int n_callers;
- // Array of callers, for matching stack traces. First one (name of f=
n
- // where err occurs) is mandatory; rest are optional.
- SuppLoc* callers;
-
- /* The tool-specific part */
- SuppKind skind; // What kind of suppression. Must use the range (0=
..).
- Char* string; // String -- use is optional. NULL by default.
- void* extra; // Anything else -- use is optional. NULL by defau=
lt.
-};
-
-SuppKind VG_(get_supp_kind) ( Supp* su )
-{
- return su->skind;
-}
-
-Char* VG_(get_supp_string) ( Supp* su )
-{
- return su->string;
-}
-
-void* VG_(get_supp_extra) ( Supp* su )
-{
- return su->extra;
-}
-
-
-void VG_(set_supp_kind) ( Supp* su, SuppKind skind )
-{
- su->skind =3D skind;
-}
-
-void VG_(set_supp_string) ( Supp* su, Char* string )
-{
- su->string =3D string;
-}
-
-void VG_(set_supp_extra) ( Supp* su, void* extra )
-{
- su->extra =3D extra;
-}
-
-
-/*------------------------------------------------------------*/
-/*--- Helper fns ---*/
-/*------------------------------------------------------------*/
-
-/* Compare error contexts, to detect duplicates. Note that if they
- are otherwise the same, the faulting addrs and associated rwoffsets
- are allowed to be different. */
-static Bool eq_Error ( VgRes res, Error* e1, Error* e2 )
-{
- if (e1->ekind !=3D e2->ekind)=20
- return False;
- if (!VG_(eq_ExeContext)(res, e1->where, e2->where))
- return False;
-
- switch (e1->ekind) {
- // case ThreadErr:
- // case MutexErr:
- // vg_assert(VG_(needs).core_errors);
- // return VG_(tm_error_equal)(res, e1, e2);
- default:=20
- if (VG_(needs).tool_errors)
- return TL_(eq_Error)(res, e1, e2);
- else {
- VG_(printf)("\nUnhandled error type: %u. VG_(needs).tool_err=
ors\n"
- "probably needs to be set.\n",
- e1->ekind);
- VG_(tool_panic)("unhandled error type");
- }
- }
-}
-
-static void pp_Error ( Error* err, Bool printCount )
-{
- if (printCount)
- VG_(message)(Vg_UserMsg, "Observed %d times:", err->count );
- if (err->tid > 0 && err->tid !=3D last_tid_printed) {
- VG_(message)(Vg_UserMsg, "Thread %d:", err->tid );
- last_tid_printed =3D err->tid;
- }
-
- switch (err->ekind) {
- // case ThreadErr:
- // case MutexErr:
- // vg_assert(VG_(needs).core_errors);
- // VG_(tm_error_print)(err);
- // break;
- default:=20
- if (VG_(needs).tool_errors)
- TL_(pp_Error)( err );
- else {
- VG_(printf)("\nUnhandled error type: %u. VG_(needs).tool_er=
rors\n"
- "probably needs to be set?\n",
- err->ekind);
- VG_(tool_panic)("unhandled error type");
- }
- }
-}
-
-/* Figure out if we want to perform a given action for this error, possi=
bly
- by asking the user. */
-Bool VG_(is_action_requested) ( Char* action, Bool* clo )
-{
- Char ch, ch2;
- Int res;
-
- if (*clo =3D=3D False)
- return False;
-
- VG_(message)(Vg_UserMsg, "");
-
- again:
- VG_(printf)(
- "=3D=3D%d=3D=3D "
- "---- %s ? --- [Return/N/n/Y/y/C/c] ---- ",=20
- VG_(getpid)(), action
- );
-
- res =3D VG_(read)(VG_(clo_input_fd), &ch, 1);
- if (res !=3D 1) goto ioerror;
- /* res =3D=3D 1 */
- if (ch =3D=3D '\n') return False;
- if (ch !=3D 'N' && ch !=3D 'n' && ch !=3D 'Y' && ch !=3D 'y'=20
- && ch !=3D 'C' && ch !=3D 'c') goto again;
-
- res =3D VG_(read)(VG_(clo_input_fd), &ch2, 1);
- if (res !=3D 1) goto ioerror;
- if (ch2 !=3D '\n') goto again;
-
- /* No, don't want to do action. */
- if (ch =3D=3D 'n' || ch =3D=3D 'N') return False;
- /* Yes, want to do action. */
- if (ch =3D=3D 'y' || ch =3D=3D 'Y') return True;
- /* No, don't want to do action, and don't ask again either. */
- vg_assert(ch =3D=3D 'c' || ch =3D=3D 'C');
-
- ioerror:
- *clo =3D False;
- return False;
-}
-
-
-/* Construct an error */
-static __inline__
-void construct_error ( Error* err, ThreadId tid, ErrorKind ekind, Addr a=
,
- Char* s, void* extra, ExeContext* where )
-{
- tl_assert(tid < VG_N_THREADS);
-
- /* Core-only parts */
- err->next =3D NULL;
- err->supp =3D NULL;
- err->count =3D 1;
- err->tid =3D tid;
- if (NULL =3D=3D where)
- err->where =3D VG_(record_ExeContext)( tid );
- else
- err->where =3D where;
-
- /* Tool-relevant parts */
- err->ekind =3D ekind;
- err->addr =3D a;
- err->extra =3D extra;
- err->string =3D s;
-
- /* sanity... */
- vg_assert( tid < VG_N_THREADS );
-}
-
-static void printSuppForIp(UInt n, Addr ip)
-{
- static UChar buf[VG_ERRTXT_LEN];
-
- if ( VG_(get_fnname_nodemangle) (ip, buf, VG_ERRTXT_LEN) ) {
- VG_(printf)(" fun:%s\n", buf);
- } else if ( VG_(get_objname)(ip, buf+7, VG_ERRTXT_LEN-7) ) {
- VG_(printf)(" obj:%s\n", buf);
- } else {
- VG_(printf)(" ???:??? "
- "# unknown, suppression will not work, sorry\n");
- }
-}
-
-static void gen_suppression(Error* err)
-{
- ExeContext* ec =3D VG_(get_error_where)(err);
- Int stop_at =3D VG_(clo_backtrace_size);
-
- /* At most VG_MAX_SUPP_CALLERS names */
- if (stop_at > VG_MAX_SUPP_CALLERS) stop_at =3D VG_MAX_SUPP_CALLERS;
- vg_assert(stop_at > 0);
-
- VG_(printf)("{\n");
- VG_(printf)(" <insert a suppression name here>\n");
-
- if (ThreadErr =3D=3D err->ekind || MutexErr =3D=3D err->ekind) {
- VG_(printf)(" core:PThread\n");
-
- } else {
- Char* name =3D TL_(get_error_name)(err);
- if (NULL =3D=3D name) {
- VG_(message)(Vg_UserMsg,=20
- "(tool does not allow error to be suppressed)");
- return;
- }
- VG_(printf)(" %s:%s\n", VG_(details).name, name);
- TL_(print_extra_suppression_info)(err);
- }
-
- // Print stack trace elements
- VG_(apply_StackTrace)(printSuppForIp, VG_(extract_StackTrace)(ec), st=
op_at);
-
- VG_(printf)("}\n");
-}
-
-static=20
-void do_actions_on_error(Error* err, Bool allow_db_attach)
-{
- Bool still_noisy =3D True;
-
- /* Perhaps we want a debugger attach at this point? */
- if (allow_db_attach &&
- VG_(is_action_requested)( "Attach to debugger", & VG_(clo_db_atta=
ch) ))=20
- {
- VG_(printf)("starting debugger\n");
- VG_(start_debugger)( err->tid );
- }
- /* Or maybe we want to generate the error's suppression? */
- if (VG_(clo_gen_suppressions) =3D=3D 2
- || (VG_(clo_gen_suppressions) =3D=3D 1
- && VG_(is_action_requested)( "Print suppression",
- &still_noisy ))
- ) {
- gen_suppression(err);
- if (VG_(clo_gen_suppressions) =3D=3D 1 && !still_noisy)
- VG_(clo_gen_suppressions) =3D 0;
- }
-}
-
-/* Shared between VG_(maybe_record_error)() and VG_(unique_error)(),
- just for pretty printing purposes. */
-static Bool is_first_shown_context =3D True;
-
-/* Top-level entry point to the error management subsystem.
- All detected errors are notified here; this routine decides if/when t=
he
- user should see the error. */
-void VG_(maybe_record_error) ( ThreadId tid,=20
- ErrorKind ekind, Addr a, Char* s, void* e=
xtra )
-{
- Error err;
- Error* p;
- Error* p_prev;
- UInt extra_size;
- VgRes exe_res =3D Vg_MedRes;
- static Bool stopping_message =3D False;
- static Bool slowdown_message =3D False;
- static Int n_errs_shown =3D 0;
-
- /* After M_COLLECT_NO_ERRORS_AFTER_SHOWN different errors have
- been found, or M_COLLECT_NO_ERRORS_AFTER_FOUND total errors
- have been found, just refuse to collect any more. This stops
- the burden of the error-management system becoming excessive in
- extremely buggy programs, although it does make it pretty
- pointless to continue the Valgrind run after this point. */
- if (VG_(clo_error_limit)=20
- && (n_errs_shown >=3D M_COLLECT_NO_ERRORS_AFTER_SHOWN
- || n_errs_found >=3D M_COLLECT_NO_ERRORS_AFTER_FOUND)) {
- if (!stopping_message) {
- VG_(message)(Vg_UserMsg, "");
-
- if (n_errs_shown >=3D M_COLLECT_NO_ERRORS_AFTER_SHOWN) {
- VG_(message)(Vg_UserMsg,=20
- "More than %d different errors detected. "
- "I'm not reporting any more.",
- M_COLLECT_NO_ERRORS_AFTER_SHOWN );
- } else {
- VG_(message)(Vg_UserMsg,=20
- "More than %d total errors detected. "
- "I'm not reporting any more.",
- M_COLLECT_NO_ERRORS_AFTER_FOUND );
- }
-
- VG_(message)(Vg_UserMsg,=20
- "Final error counts will be inaccurate. Go fix your program=
!");
- VG_(message)(Vg_UserMsg,=20
- "Rerun with --error-limit=3Dno to disable this cutoff. Note=
");
- VG_(message)(Vg_UserMsg,=20
- "that errors may occur in your program without prior warning=
from");
- VG_(message)(Vg_UserMsg,=20
- "Valgrind, because errors are no longer being displayed.");
- VG_(message)(Vg_UserMsg, "");
- stopping_message =3D True;
- }
- return;
- }
-
- /* After M_COLLECT_ERRORS_SLOWLY_AFTER different errors have
- been found, be much more conservative about collecting new
- ones. */
- if (n_errs_shown >=3D M_COLLECT_ERRORS_SLOWLY_AFTER) {
- exe_res =3D Vg_LowRes;
- if (!slowdown_message) {
- VG_(message)(Vg_UserMsg, "");
- VG_(message)(Vg_UserMsg,=20
- "More than %d errors detected. Subsequent errors",
- M_COLLECT_ERRORS_SLOWLY_AFTER);
- VG_(message)(Vg_UserMsg,=20
- "will still be recorded, but in less detail than before.");
- slowdown_message =3D True;
- }
- }
-
- /* Build ourselves the error */
- construct_error ( &err, tid, ekind, a, s, extra, NULL );
-
- /* First, see if we've got an error record matching this one. */
- p =3D errors;
- p_prev =3D NULL;
- while (p !=3D NULL) {
- if (eq_Error(exe_res, p, &err)) {
- /* Found it. */
- p->count++;
- if (p->supp !=3D NULL) {
- /* Deal correctly with suppressed errors. */
- p->supp->count++;
- n_errs_suppressed++; =20
- } else {
- n_errs_found++;
- }
-
- /* Move p to the front of the list so that future searches
- for it are faster. */
- if (p_prev !=3D NULL) {
- vg_assert(p_prev->next =3D=3D p);
- p_prev->next =3D p->next;
- p->next =3D errors;
- errors =3D p;
- }
-
- return;
- }
- p_prev =3D p;
- p =3D p->next;
- }
-
- /* Didn't see it. Copy and add. */
-
- /* OK, we're really going to collect it. The context is on the stack=
and
- will disappear shortly, so we must copy it. First do the main
- (non-`extra') part.
- =20
- Then TL_(update_extra) can update the `extra' part. This is for w=
hen
- there are more details to fill in which take time to work out but
- don't affect our earlier decision to include the error -- by
- postponing those details until now, we avoid the extra work in the
- case where we ignore the error. Ugly.
-
- Then, if there is an `extra' part, copy it too, using the size tha=
t
- TL_(update_extra) returned. Also allow for people using the void*
- extra field for a scalar value like an integer.
- */
-
- /* copy main part */
- p =3D VG_(arena_malloc)(VG_AR_ERRORS, sizeof(Error));
- *p =3D err;
-
- /* update `extra' */
- switch (ekind) {
- // case ThreadErr:
- // case MutexErr:
- // vg_assert(VG_(needs).core_errors);
- // extra_size =3D VG_(tm_error_update_extra)(p);
- // break;
- default:
- vg_assert(VG_(needs).tool_errors);
- extra_size =3D TL_(update_extra)(p);
- break;
- }
-
- /* copy block pointed to by `extra', if there is one */
- if (NULL !=3D p->extra && 0 !=3D extra_size) {=20
- void* new_extra =3D VG_(malloc)(extra_size);
- VG_(memcpy)(new_extra, p->extra, extra_size);
- p->extra =3D new_extra;
- }
-
- p->next =3D errors;
- p->supp =3D is_suppressible_error(&err);
- errors =3D p;
- if (p->supp =3D=3D NULL) {
- n_errs_found++;
- if (!is_first_shown_context)
- VG_(message)(Vg_UserMsg, "");
- pp_Error(p, False);
- is_first_shown_context =3D False;
- n_errs_shown++;
- do_actions_on_error(p, /*allow_db_attach*/True);
- } else {
- n_errs_suppressed++;
- p->supp->count++;
- }
-}
-
-/* Second top-level entry point to the error management subsystem, for
- errors that the tool wants to report immediately, eg. because they're
- guaranteed to only happen once. This avoids all the recording and
- comparing stuff. But they can be suppressed; returns True if it is
- suppressed. Bool `print_error' dictates whether to print the error.=20
- Bool `count_error' dictates whether to count the error in n_errs_foun=
d.
-*/
-Bool VG_(unique_error) ( ThreadId tid, ErrorKind ekind, Addr a, Char* s,
- void* extra, ExeContext* where, Bool print_erro=
r,
- Bool allow_db_attach, Bool count_error )
-{
- Error err;
-
- /* Build ourselves the error */
- construct_error ( &err, tid, ekind, a, s, extra, where );
-
- /* Unless it's suppressed, we're going to show it. Don't need to mak=
e
- a copy, because it's only temporary anyway.
-
- Then update the `extra' part with TL_(update_extra), because that =
can
- have an affect on whether it's suppressed. Ignore the size return
- value of TL_(update_extra), because we're not copying `extra'. */
- (void)TL_(update_extra)(&err);
-
- if (NULL =3D=3D is_suppressible_error(&err)) {
- if (count_error)
- n_errs_found++;
-
- if (print_error) {
- if (!is_first_shown_context)
- VG_(message)(Vg_UserMsg, "");
- pp_Error(&err, False);
- is_first_shown_context =3D False;
- }
- do_actions_on_error(&err, allow_db_attach);
-
- return False;
-
- } else {
- n_errs_suppressed++;
- return True;
- }
-}
-
-
-/*------------------------------------------------------------*/
-/*--- Exported fns ---*/
-/*------------------------------------------------------------*/
-
-/* This is called not from generated code but from the scheduler */
-void VG_(show_all_errors) ( void )
-{
- Int i, n_min;
- Int n_err_contexts, n_supp_contexts;
- Error *p, *p_min;
- Supp *su;
- Bool any_supp;
-
- if (VG_(clo_verbosity) =3D=3D 0)
- return;
-
- n_err_contexts =3D 0;
- for (p =3D errors; p !=3D NULL; p =3D p->next) {
- if (p->supp =3D=3D NULL)
- n_err_contexts++;
- }
-
- n_supp_contexts =3D 0;
- for (su =3D suppressions; su !=3D NULL; su =3D su->next) {
- if (su->count > 0)
- n_supp_contexts++;
- }
- VG_(message)(Vg_UserMsg,
- "ERROR SUMMARY: "
- "%d errors from %d contexts (suppressed: %d from %d)",
- n_errs_found, n_err_contexts,=20
- ...
[truncated message content] |