|
From: <sv...@va...> - 2005-04-24 12:33:30
|
Author: sewardj
Date: 2005-04-24 13:33:12 +0100 (Sun, 24 Apr 2005)
New Revision: 3555
Added:
trunk/coregrind/m_errormgr.c
trunk/coregrind/m_execontext.c
trunk/coregrind/m_stacktrace.c
Removed:
trunk/coregrind/errormgr.c
trunk/coregrind/execontext.c
trunk/coregrind/stacktrace.c
Modified:
trunk/coregrind/Makefile.am
Log:
Rename the first three modules as per naming scheme.
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-24 12:19:13 UTC (rev 3554)
+++ trunk/coregrind/Makefile.am 2005-04-24 12:33:12 UTC (rev 3555)
@@ -52,9 +52,9 @@
valgrind_LDADD=3D
=20
stage2_SOURCES =3D \
- errormgr.c \
- execontext.c \
- stacktrace.c \
+ m_errormgr.c \
+ m_execontext.c \
+ m_stacktrace.c \
ume.c \
\
vg_scheduler.c \
Deleted: 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-24 12:19:13 UTC (rev 3554)
+++ trunk/coregrind/errormgr.c 2005-04-24 12:33:12 UTC (rev 3555)
@@ -1,1031 +0,0 @@
-
-/*--------------------------------------------------------------------*/
-/*--- 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 ---*/
-/*--------------------------------------------------------------------*/
Deleted: trunk/coregrind/execontext.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/execontext.c 2005-04-24 12:19:13 UTC (rev 3554)
+++ trunk/coregrind/execontext.c 2005-04-24 12:33:12 UTC (rev 3555)
@@ -1,256 +0,0 @@
-/*--------------------------------------------------------------------*/
-/*--- execontext.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"
-
-/*------------------------------------------------------------*/
-/*--- Low-level ExeContext storage. ---*/
-/*------------------------------------------------------------*/
-
-/* The first 4 IP values are used in comparisons do remove duplicate err=
ors,
- and for comparing against suppression specifications. The rest are
- purely informational (but often important). */
-
-struct _ExeContext {
- struct _ExeContext * next;
- /* Variable-length array. The size is VG_(clo_backtrace_size); at
- least 1, at most VG_DEEPEST_BACKTRACE. [0] is the current IP,
- [1] is its caller, [2] is the caller of [1], etc. */
- Addr ips[0];
-};
-
-/* Number of lists in which we keep track of ExeContexts. Should be
- prime. */
-#define N_EC_LISTS 4999 /* a prime number */
-
-/* The idea is only to ever store any one context once, so as to save
- space and make exact comparisons faster. */
-
-static ExeContext* ec_list[N_EC_LISTS];
-
-/* Stats only: the number of times the system was searched to locate a
- context. */
-static UInt ec_searchreqs;
-
-/* Stats only: the number of full context comparisons done. */
-static UInt ec_searchcmps;
-
-/* Stats only: total number of stored contexts. */
-static UInt ec_totstored;
-
-/* Number of 2, 4 and (fast) full cmps done. */
-static UInt ec_cmp2s;
-static UInt ec_cmp4s;
-static UInt ec_cmpAlls;
-
-
-/*------------------------------------------------------------*/
-/*--- Exported functions. ---*/
-/*------------------------------------------------------------*/
-
-
-/* Initialise this subsystem. */
-static void init_ExeContext_storage ( void )
-{
- Int i;
- static Bool init_done =3D False;
- if (init_done)
- return;
- ec_searchreqs =3D 0;
- ec_searchcmps =3D 0;
- ec_totstored =3D 0;
- ec_cmp2s =3D 0;
- ec_cmp4s =3D 0;
- ec_cmpAlls =3D 0;
- for (i =3D 0; i < N_EC_LISTS; i++)
- ec_list[i] =3D NULL;
- init_done =3D True;
-}
-
-
-/* Print stats. */
-void VG_(print_ExeContext_stats) ( void )
-{
- init_ExeContext_storage();
- VG_(message)(Vg_DebugMsg,=20
- " exectx: %d lists, %d contexts (avg %d per list)",
- N_EC_LISTS, ec_totstored,=20
- ec_totstored / N_EC_LISTS=20
- );
- VG_(message)(Vg_DebugMsg,=20
- " exectx: %d searches, %d full compares (%d per 1000)",
- ec_searchreqs, ec_searchcmps,=20
- ec_searchreqs =3D=3D 0=20
- ? 0=20
- : (UInt)( (((ULong)ec_searchcmps) * 1000)=20
- / ((ULong)ec_searchreqs ))=20
- );
- VG_(message)(Vg_DebugMsg,=20
- " exectx: %d cmp2, %d cmp4, %d cmpAll",
- ec_cmp2s, ec_cmp4s, ec_cmpAlls=20
- );
-}
-
-
-/* Print an ExeContext. */
-void VG_(pp_ExeContext) ( ExeContext* ec )
-{
- VG_(pp_StackTrace)( ec->ips, VG_(clo_backtrace_size) );
-}
-
-
-/* Compare two ExeContexts, comparing all callers. */
-Bool VG_(eq_ExeContext) ( VgRes res, ExeContext* e1, ExeContext* e2 )
-{
- if (e1 =3D=3D NULL || e2 =3D=3D NULL)=20
- return False;
- switch (res) {
- case Vg_LowRes:
- /* Just compare the top two callers. */
- ec_cmp2s++;
- if (e1->ips[0] !=3D e2->ips[0]) return False;
-
- if (VG_(clo_backtrace_size) < 2) return True;
- if (e1->ips[1] !=3D e2->ips[1]) return False;
- return True;
-
- case Vg_MedRes:
- /* Just compare the top four callers. */
- ec_cmp4s++;
- if (e1->ips[0] !=3D e2->ips[0]) return False;
-
- if (VG_(clo_backtrace_size) < 2) return True;
- if (e1->ips[1] !=3D e2->ips[1]) return False;
-
- if (VG_(clo_backtrace_size) < 3) return True;
- if (e1->ips[2] !=3D e2->ips[2]) return False;
-
- if (VG_(clo_backtrace_size) < 4) return True;
- if (e1->ips[3] !=3D e2->ips[3]) return False;
- return True;
-
- case Vg_HighRes:
- ec_cmpAlls++;
- /* Compare them all -- just do pointer comparison. */
- if (e1 !=3D e2) return False;
- return True;
-
- default:
- VG_(core_panic)("VG_(eq_ExeContext): unrecognised VgRes");
- }
-}
-
-/* This guy is the head honcho here. Take a snapshot of the client's
- stack. Search our collection of ExeContexts to see if we already
- have it, and if not, allocate a new one. Either way, return a
- pointer to the context. If there is a matching context we
- guarantee to not allocate a new one. Thus we never store
- duplicates, and so exact equality can be quickly done as equality
- on the returned ExeContext* values themselves. Inspired by Hugs's
- Text type. =20
-*/
-ExeContext* VG_(record_ExeContext) ( ThreadId tid )
-{
- Int i;
- Addr ips[VG_DEEPEST_BACKTRACE];
- Bool same;
- UWord hash;
- ExeContext* new_ec;
- ExeContext* list;
-
- VGP_PUSHCC(VgpExeContext);
-
- init_ExeContext_storage();
- vg_assert(VG_(clo_backtrace_size) >=3D 1=20
- && VG_(clo_backtrace_size) <=3D VG_DEEPEST_BACKTRACE);
-
- VG_(get_StackTrace)( tid, ips, VG_(clo_backtrace_size) );
-
- /* Now figure out if we've seen this one before. First hash it so
- as to determine the list number. */
-
- hash =3D 0;
- for (i =3D 0; i < VG_(clo_backtrace_size); i++) {
- hash ^=3D ips[i];
- hash =3D (hash << 29) | (hash >> 3);
- }
- hash =3D hash % N_EC_LISTS;
-
- /* And (the expensive bit) look a matching entry in the list. */
-
- ec_searchreqs++;
-
- list =3D ec_list[hash];
-
- while (True) {
- if (list =3D=3D NULL) break;
- ec_searchcmps++;
- same =3D True;
- for (i =3D 0; i < VG_(clo_backtrace_size); i++) {
- if (list->ips[i] !=3D ips[i]) {
- same =3D False;
- break;=20
- }
- }
- if (same) break;
- list =3D list->next;
- }
-
- if (list !=3D NULL) {
- /* Yay! We found it. */
- VGP_POPCC(VgpExeContext);
- return list;
- }
-
- /* Bummer. We have to allocate a new context record. */
- ec_totstored++;
-
- new_ec =3D VG_(arena_malloc)( VG_AR_EXECTXT,=20
- sizeof(struct _ExeContext *)=20
- + VG_(clo_backtrace_size) * sizeof(Addr) =
);
-
- for (i =3D 0; i < VG_(clo_backtrace_size); i++)
- new_ec->ips[i] =3D ips[i];
-
- new_ec->next =3D ec_list[hash];
- ec_list[hash] =3D new_ec;
-
- VGP_POPCC(VgpExeContext);
- return new_ec;
-}
-
-StackTrace VG_(extract_StackTrace) ( ExeContext* e )
-{ =20
- return e->ips;
-} =20
-
-/*--------------------------------------------------------------------*/
-/*--- end ---*/
-/*--------------------------------------------------------------------*/
Copied: trunk/coregrind/m_errormgr.c (from rev 3550, trunk/coregrind/erro=
rmgr.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-24 00:21:01 UTC (rev 3550)
+++ trunk/coregrind/m_errormgr.c 2005-04-24 12:33:12 UTC (rev 3555)
@@ -0,0 +1,1031 @@
+
+/*--------------------------------------------------------------------*/
+/*--- Management of error messages. m_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 t...
[truncated message content] |