Merge in changes from the 2.4.0 line. This basically brings in the
overhaul of the thread support. Many things are now probably broken,
but at least with --tool=none, simple and not-so-simple threaded and
non-thread programs work.
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3265 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/coregrind/vg_errcontext.c b/coregrind/vg_errcontext.c
index 612f666..5ca241b 100644
--- a/coregrind/vg_errcontext.c
+++ b/coregrind/vg_errcontext.c
@@ -51,6 +51,7 @@
/* forwards ... */
static Supp* is_suppressible_error ( Error* err );
+static ThreadId last_tid_printed = 1;
/*------------------------------------------------------------*/
/*--- Error type ---*/
@@ -58,11 +59,6 @@
/* Note: it is imperative this doesn't overlap with (0..) at all, as tools
* effectively extend it by defining their own enums in the (0..) range. */
-typedef
- enum {
- PThreadErr = -1, // Pthreading error
- }
- CoreErrorKind;
/* Errors. Extensible (via the 'extra' field). Tools can use a normal
enum (with element values in the normal range (0..)) for `ekind'.
@@ -130,15 +126,26 @@
}
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 {
+ 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.
Tools can use a normal enum (with element values in the normal range
@@ -147,10 +154,12 @@
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.
- /* First two (name of fn where err occurs, and immediate caller)
- * are mandatory; extra two are optional. */
- SuppLocTy caller_ty[VG_N_SUPP_CALLERS];
- Char* caller [VG_N_SUPP_CALLERS];
+
+ // Length of 'callers'
+ Int n_callers;
+ // Array of callers, for matching stack traces. First one (name of fn
+ // 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..).
@@ -205,13 +214,10 @@
return False;
switch (e1->ekind) {
- case PThreadErr:
- vg_assert(VG_(needs).core_errors);
- if (e1->string == e2->string)
- return True;
- if (0 == VG_(strcmp)(e1->string, e2->string))
- return True;
- return False;
+ // case ThreadErr:
+ // case MutexErr:
+ // vg_assert(VG_(needs).core_errors);
+ // return VG_(tm_error_equal)(res, e1, e2);
default:
if (VG_(needs).tool_errors)
return TL_(eq_Error)(res, e1, e2);
@@ -228,15 +234,17 @@
{
if (printCount)
VG_(message)(Vg_UserMsg, "Observed %d times:", err->count );
- if (err->tid > 1)
+ if (err->tid > 0 && err->tid != last_tid_printed) {
VG_(message)(Vg_UserMsg, "Thread %d:", err->tid );
+ last_tid_printed = err->tid;
+ }
switch (err->ekind) {
- case PThreadErr:
- vg_assert(VG_(needs).core_errors);
- VG_(message)(Vg_UserMsg, "%s", err->string );
- VG_(pp_ExeContext)(err->where);
- break;
+ // case ThreadErr:
+ // case MutexErr:
+ // vg_assert(VG_(needs).core_errors);
+ // VG_(tm_error_print)(err);
+ // break;
default:
if (VG_(needs).tool_errors)
TL_(pp_Error)( err );
@@ -292,8 +300,7 @@
}
-// Initialisation picks out values from the appropriate ThreadState as
-// necessary.
+/* Construct an error */
static __inline__
void construct_error ( Error* err, ThreadId tid, ErrorKind ekind, Addr a,
Char* s, void* extra, ExeContext* where )
@@ -328,14 +335,14 @@
ExeContext* ec = VG_(get_error_where)(err);
Int stop_at = VG_(clo_backtrace_size);
- /* At most VG_N_SUPP_CALLERS names */
- if (stop_at > VG_N_SUPP_CALLERS) stop_at = VG_N_SUPP_CALLERS;
+ /* At most VG_MAX_SUPP_CALLERS names */
+ if (stop_at > VG_MAX_SUPP_CALLERS) stop_at = VG_MAX_SUPP_CALLERS;
vg_assert(stop_at > 0);
VG_(printf)("{\n");
VG_(printf)(" <insert a suppression name here>\n");
- if (PThreadErr == err->ekind) {
+ if (ThreadErr == err->ekind || MutexErr == err->ekind) {
VG_(printf)(" core:PThread\n");
} else {
@@ -528,16 +535,24 @@
p = VG_(arena_malloc)(VG_AR_ERRORS, sizeof(Error));
*p = err;
- /* update `extra', for non-core errors (core ones don't use 'extra') */
- if (VG_(needs).tool_errors && PThreadErr != ekind) {
- extra_size = TL_(update_extra)(p);
+ /* update `extra' */
+ switch (ekind) {
+ // case ThreadErr:
+ // case MutexErr:
+ // vg_assert(VG_(needs).core_errors);
+ // extra_size = VG_(tm_error_update_extra)(p);
+ // break;
+ default:
+ vg_assert(VG_(needs).tool_errors);
+ extra_size = TL_(update_extra)(p);
+ break;
+ }
- /* copy block pointed to by `extra', if there is one */
- if (NULL != p->extra && 0 != extra_size) {
- void* new_extra = VG_(malloc)(extra_size);
- VG_(memcpy)(new_extra, p->extra, extra_size);
- p->extra = new_extra;
- }
+ /* copy block pointed to by `extra', if there is one */
+ if (NULL != p->extra && 0 != extra_size) {
+ void* new_extra = VG_(malloc)(extra_size);
+ VG_(memcpy)(new_extra, p->extra, extra_size);
+ p->extra = new_extra;
}
p->next = vg_errors;
@@ -608,12 +623,6 @@
/* These are called not from generated code but from the scheduler */
-void VG_(record_pthread_error) ( ThreadId tid, Char* msg )
-{
- if (! VG_(needs).core_errors) return;
- VG_(maybe_record_error)( tid, PThreadErr, /*addr*/0, msg, /*extra*/NULL );
-}
-
void VG_(show_all_errors) ( void )
{
Int i, n_min;
@@ -746,16 +755,16 @@
(fun: or obj:) part.
Returns False if failed.
*/
-static Bool setLocationTy ( Char** p_caller, SuppLocTy* p_ty )
+static Bool setLocationTy ( SuppLoc* p )
{
- if (VG_(strncmp)(*p_caller, "fun:", 4) == 0) {
- (*p_caller) += 4;
- *p_ty = FunName;
+ if (VG_(strncmp)(p->name, "fun:", 4) == 0) {
+ p->name += 4;
+ p->ty = FunName;
return True;
}
- if (VG_(strncmp)(*p_caller, "obj:", 4) == 0) {
- (*p_caller) += 4;
- *p_ty = ObjName;
+ if (VG_(strncmp)(p->name, "obj:", 4) == 0) {
+ p->name += 4;
+ p->ty = ObjName;
return True;
}
VG_(printf)("location should start with fun: or obj:\n");
@@ -787,10 +796,12 @@
{
# define N_BUF 200
Int fd, i;
- Bool eof, too_many_contexts = False;
+ Bool eof;
Char buf[N_BUF+1];
Char* tool_names;
Char* supp_name;
+ Char* err_str = NULL;
+ SuppLoc tmp_callers[VG_MAX_SUPP_CALLERS];
fd = VG_(open)( filename, VKI_O_RDONLY, 0 );
if (fd < 0) {
@@ -799,32 +810,42 @@
VG_(exit)(1);
}
+#define BOMB(S) { err_str = S; goto syntax_error; }
+
while (True) {
/* Assign and initialise the two suppression halves (core and tool) */
Supp* supp;
supp = VG_(arena_malloc)(VG_AR_CORE, sizeof(Supp));
supp->count = 0;
- for (i = 0; i < VG_N_SUPP_CALLERS; i++) supp->caller[i] = NULL;
+
+ // Initialise temporary reading-in buffer.
+ for (i = 0; i < VG_MAX_SUPP_CALLERS; i++) {
+ tmp_callers[i].ty = NoName;
+ tmp_callers[i].name = NULL;
+ }
+
supp->string = supp->extra = NULL;
eof = VG_(get_line) ( fd, buf, N_BUF );
if (eof) break;
- if (!VG_STREQ(buf, "{")) goto syntax_error;
+ if (!VG_STREQ(buf, "{")) BOMB("expected '{' or end-of-file");
eof = VG_(get_line) ( fd, buf, N_BUF );
- if (eof || VG_STREQ(buf, "}")) goto syntax_error;
+
+ if (eof || VG_STREQ(buf, "}")) BOMB("unexpected '}'");
+
supp->sname = VG_(arena_strdup)(VG_AR_CORE, buf);
eof = VG_(get_line) ( fd, buf, N_BUF );
- if (eof) goto syntax_error;
+ if (eof) BOMB("unexpected end-of-file");
/* Check it has the "tool1,tool2,...:supp" form (look for ':') */
i = 0;
while (True) {
if (buf[i] == ':') break;
- if (buf[i] == '\0') goto syntax_error;
+ if (buf[i] == '\0') BOMB("malformed 'tool1,tool2,...:supp' line");
i++;
}
buf[i] = '\0'; /* Replace ':', splitting into two strings */
@@ -832,31 +853,29 @@
tool_names = & buf[0];
supp_name = & buf[i+1];
- /* Is it a core suppression? */
if (VG_(needs).core_errors && tool_name_present("core", tool_names))
{
+ // A core suppression
if (VG_STREQ(supp_name, "PThread"))
supp->skind = PThreadSupp;
else
- goto syntax_error;
+ BOMB("unknown core suppression type");
}
-
- /* Is it a tool suppression? */
else if (VG_(needs).tool_errors &&
tool_name_present(VG_(details).name, tool_names))
{
- if (TL_(recognised_suppression)(supp_name, supp))
- {
+ // A tool suppression
+ if (TL_(recognised_suppression)(supp_name, supp)) {
/* Do nothing, function fills in supp->skind */
- } else
- goto syntax_error;
+ } else {
+ BOMB("unknown tool suppression type");
+ }
}
-
else {
- /* Ignore rest of suppression */
+ // Ignore rest of suppression
while (True) {
eof = VG_(get_line) ( fd, buf, N_BUF );
- if (eof) goto syntax_error;
+ if (eof) BOMB("unexpected end-of-file");
if (VG_STREQ(buf, "}"))
break;
}
@@ -864,32 +883,46 @@
}
if (VG_(needs).tool_errors &&
- !TL_(read_extra_suppression_info)(fd, buf, N_BUF, supp))
- goto syntax_error;
-
- /* "i > 0" ensures at least one caller read. */
- for (i = 0; i <= VG_N_SUPP_CALLERS; i++) {
- eof = VG_(get_line) ( fd, buf, N_BUF );
- if (eof) goto syntax_error;
- if (i > 0 && VG_STREQ(buf, "}"))
- break;
- if (i == VG_N_SUPP_CALLERS)
- break;
- supp->caller[i] = VG_(arena_strdup)(VG_AR_CORE, buf);
- if (!setLocationTy(&(supp->caller[i]), &(supp->caller_ty[i])))
- goto syntax_error;
+ !TL_(read_extra_suppression_info)(fd, buf, N_BUF, supp))
+ {
+ BOMB("bad or missing extra suppression info");
}
- /* make sure to grab the '}' if the num callers is >=
- VG_N_SUPP_CALLERS */
+ i = 0;
+ while (True) {
+ eof = 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 == VG_MAX_SUPP_CALLERS)
+ BOMB("too many callers in stack trace");
+ if (i > 0 && i >= VG_(clo_backtrace_size))
+ break;
+ tmp_callers[i].name = 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 >= VG_(clo_backtrace_size), ignore any extra
+ // lines and grab the '}'.
if (!VG_STREQ(buf, "}")) {
- // Don't just ignore extra lines -- abort. (Someone complained
- // about silent ignoring of lines in bug #77922.)
- //do {
- // eof = VG_(get_line) ( fd, buf, N_BUF );
- //} while (!eof && !VG_STREQ(buf, "}"));
- too_many_contexts = True;
- goto syntax_error;
+ do {
+ eof = VG_(get_line) ( fd, buf, N_BUF );
+ } while (!eof && !VG_STREQ(buf, "}"));
+ }
+
+ // Copy tmp_callers[] into supp->callers[]
+ supp->n_callers = i;
+ supp->callers = VG_(arena_malloc)(VG_AR_CORE, i*sizeof(SuppLoc));
+ for (i = 0; i < supp->n_callers; i++) {
+ supp->callers[i] = tmp_callers[i];
}
supp->next = vg_suppressions;
@@ -899,26 +932,14 @@
return;
syntax_error:
- if (eof) {
- VG_(message)(Vg_UserMsg,
- "FATAL: in suppressions file `%s': unexpected EOF",
- filename );
- } else if (too_many_contexts) {
- VG_(message)(Vg_UserMsg,
- "FATAL: in suppressions file: `%s': at %s:",
- filename, buf );
- VG_(message)(Vg_UserMsg,
- "too many lines (limit of %d contexts in suppressions)",
- VG_N_SUPP_CALLERS);
- } else {
- VG_(message)(Vg_UserMsg,
- "FATAL: in suppressions file: `%s': syntax error on: %s",
- filename, buf );
- }
+ VG_(message)(Vg_UserMsg,
+ "FATAL: in suppressions file `%s': %s", filename, err_str );
+
VG_(close)(fd);
VG_(message)(Vg_UserMsg, "exiting now.");
VG_(exit)(1);
+# undef BOMB
# undef N_BUF
}
@@ -936,24 +957,12 @@
}
}
-/* Return the name of an erring fn in a way which is useful
- for comparing against the contents of a suppressions file.
- Doesn't demangle the fn name, because we want to refer to
- mangled names in the suppressions file.
-*/
-static void get_objname_fnname ( Addr a, Char* obj_buf, Int n_obj_buf,
- Char* fun_buf, Int n_fun_buf )
-{
- (void)VG_(get_objname) ( a, obj_buf, n_obj_buf );
- (void)VG_(get_fnname_nodemangle)( a, fun_buf, n_fun_buf );
-}
-
-static __inline__
+static
Bool supp_matches_error(Supp* su, Error* err)
{
switch (su->skind) {
case PThreadSupp:
- return (err->ekind == PThreadErr);
+ return (err->ekind == ThreadErr || err->ekind == MutexErr);
default:
if (VG_(needs).tool_errors) {
return TL_(error_matches_suppression)(err, su);
@@ -967,22 +976,28 @@
}
}
-static __inline__
-Bool supp_matches_callers(Supp* su, Char caller_obj[][M_VG_ERRTXT],
- Char caller_fun[][M_VG_ERRTXT])
+static
+Bool supp_matches_callers(Error* err, Supp* su)
{
Int i;
+ Char caller_name[M_VG_ERRTXT];
- for (i = 0; i < VG_N_SUPP_CALLERS && su->caller[i] != NULL; i++) {
- switch (su->caller_ty[i]) {
- case ObjName: if (VG_(string_match)(su->caller[i],
- caller_obj[i])) break;
- return False;
- case FunName: if (VG_(string_match)(su->caller[i],
- caller_fun[i])) break;
- return False;
+ for (i = 0; i < su->n_callers; i++) {
+ Addr a = err->where->ips[i];
+ vg_assert(su->callers[i].name != NULL);
+ switch (su->callers[i].ty) {
+ case ObjName:
+ (void)VG_(get_objname)(a, caller_name, M_VG_ERRTXT);
+ break;
+
+ case FunName:
+ // Nb: mangled names used in suppressions
+ (void)VG_(get_fnname_nodemangle)(a, caller_name, M_VG_ERRTXT);
+ 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 */
@@ -995,32 +1010,13 @@
*/
static Supp* is_suppressible_error ( Error* err )
{
- Int i;
-
- static Char caller_obj[VG_N_SUPP_CALLERS][M_VG_ERRTXT];
- static Char caller_fun[VG_N_SUPP_CALLERS][M_VG_ERRTXT];
-
Supp* su;
- /* get_objname_fnname() writes the function name and object name if
- it finds them in the debug info. So the strings in the suppression
- file should match these.
- */
-
- /* Initialise these strs so they are always safe to compare, even
- if get_objname_fnname doesn't write anything to them. */
- for (i = 0; i < VG_N_SUPP_CALLERS; i++)
- caller_obj[i][0] = caller_fun[i][0] = 0;
-
- for (i = 0; i < VG_N_SUPP_CALLERS && i < VG_(clo_backtrace_size); i++) {
- get_objname_fnname ( err->where->ips[i], caller_obj[i], M_VG_ERRTXT,
- caller_fun[i], M_VG_ERRTXT );
- }
-
/* See if the error context matches any suppression. */
for (su = vg_suppressions; su != NULL; su = su->next) {
if (supp_matches_error(su, err) &&
- supp_matches_callers(su, caller_obj, caller_fun)) {
+ supp_matches_callers(err, su))
+ {
return su;
}
}
@@ -1028,5 +1024,5 @@
}
/*--------------------------------------------------------------------*/
-/*--- end vg_errcontext.c ---*/
+/*--- end ---*/
/*--------------------------------------------------------------------*/