summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPetr Machata <pmachata@redhat.com>2011-03-29 00:54:48 +0200
committerPetr Machata <pmachata@redhat.com>2011-03-29 00:54:48 +0200
commit2600729770557b3e29342b304c85f4e58a2efe28 (patch)
tree8dfbb80b59dbe794021d850d6af0c6913f3c491d
parenteda095ddccc41210e43c41a65adc8eaff55596e1 (diff)
downloadelfutils-2600729770557b3e29342b304c85f4e58a2efe28.tar.gz
dwarflint: Add filtering of duplicate messages
- we use the first string component of stream implementation of wr_message as a key to decide whether we've seen the message before. Most of the messages use streams, is why it's like that. When (if) we get back to formatting strings, that string should be even better key, because there will be less chance for compiler to do duplicate elimination etc.
-rw-r--r--dwarflint/check_debug_aranges.cc14
-rw-r--r--dwarflint/check_debug_loc_range.cc6
-rw-r--r--dwarflint/check_matching_ranges.cc14
-rw-r--r--dwarflint/check_range_out_of_scope.cc8
-rw-r--r--dwarflint/messages.cc110
-rw-r--r--dwarflint/messages.hh69
-rw-r--r--dwarflint/option.hh16
7 files changed, 192 insertions, 45 deletions
diff --git a/dwarflint/check_debug_aranges.cc b/dwarflint/check_debug_aranges.cc
index b0c84e14..0d3e3b30 100644
--- a/dwarflint/check_debug_aranges.cc
+++ b/dwarflint/check_debug_aranges.cc
@@ -129,10 +129,10 @@ hole (uint64_t start, uint64_t length, void *user)
what = cu;
cu = tmp;
}
- wr_message (mc_aranges | mc_impact_3, &where,
- ": addresses %s are covered with %s, but not with %s.\n",
- range_fmt (buf, sizeof (buf), start, start + length),
- cu, what);
+ wr_message (where, mc_aranges | mc_impact_3)
+ << "addresses " << range_fmt (buf, sizeof (buf), start, start + length)
+ << " are covered with " << cu << ", but not with " << what << "."
+ << std::endl;
}
if (sec == NULL)
@@ -170,9 +170,9 @@ aranges_coverage_add (struct coverage *aranges_coverage,
{
char buf[128];
/* Not a show stopper, this shouldn't derail high-level. */
- wr_message (mc_aranges | mc_impact_2 | mc_error, where,
- ": the range %s overlaps with another one.\n",
- range_fmt (buf, sizeof buf, begin, begin + length));
+ wr_message (*where, mc_aranges | mc_impact_2 | mc_error)
+ << "the range " << range_fmt (buf, sizeof buf, begin, begin + length)
+ << " overlaps with another one." << std::endl;
}
aranges_coverage->add (begin, length);
diff --git a/dwarflint/check_debug_loc_range.cc b/dwarflint/check_debug_loc_range.cc
index cdd69606..f87b2aa4 100644
--- a/dwarflint/check_debug_loc_range.cc
+++ b/dwarflint/check_debug_loc_range.cc
@@ -311,9 +311,9 @@ namespace
&& cov->is_overlap (cov_begin, cov_end - cov_begin))
{
/* Not a show stopper, this shouldn't derail high-level. */
- wr_message (cat | mc_impact_2 | mc_error, where,
- ": the range %s overlaps with another one.\n",
- range_fmt (buf, sizeof buf, address, end));
+ wr_message (*where, cat | mc_aranges | mc_impact_2 | mc_error)
+ << "the range " << range_fmt (buf, sizeof buf, address, end)
+ << " overlaps with another one." << std::endl;
overlap = true;
}
diff --git a/dwarflint/check_matching_ranges.cc b/dwarflint/check_matching_ranges.cc
index af46ffff..a567ce48 100644
--- a/dwarflint/check_matching_ranges.cc
+++ b/dwarflint/check_matching_ranges.cc
@@ -94,9 +94,10 @@ check_matching_ranges::check_matching_ranges (checkstack &stack,
for (range_vec::iterator it = missing.begin ();
it != missing.end (); ++it)
- wr_message (mc_ranges | mc_aranges | mc_impact_3, &where_r,
- ": missing range %s, present in .debug_aranges.\n",
- range_fmt (buf, sizeof buf, it->first, it->second));
+ wr_message (where_r, mc_ranges | mc_aranges | mc_impact_3)
+ << "missing range "
+ << range_fmt (buf, sizeof buf, it->first, it->second)
+ << ", present in .debug_aranges." << std::endl;
missing.clear ();
std::set_difference (cu_ranges.begin (), cu_ranges.end (),
@@ -105,9 +106,10 @@ check_matching_ranges::check_matching_ranges (checkstack &stack,
for (range_vec::iterator it = missing.begin ();
it != missing.end (); ++it)
- wr_message (mc_ranges | mc_aranges | mc_impact_3, &where_ar,
- ": missing range %s, present in .debug_ranges.\n",
- range_fmt (buf, sizeof buf, it->first, it->second));
+ wr_message (where_ar, mc_ranges | mc_aranges | mc_impact_3)
+ << "missing range "
+ << range_fmt (buf, sizeof buf, it->first, it->second)
+ << ", present in .debug_ranges." << std::endl;
}
}
// XXX more specific class when <dwarf> has it
diff --git a/dwarflint/check_range_out_of_scope.cc b/dwarflint/check_range_out_of_scope.cc
index 016cb38a..daa2bc3d 100644
--- a/dwarflint/check_range_out_of_scope.cc
+++ b/dwarflint/check_range_out_of_scope.cc
@@ -176,12 +176,12 @@ check_range_out_of_scope::recursively_validate
if (!result.empty ())
{
- wr_error (wh)
+ wr_message (wh, mc_error)
<< "PC range " << cov::format_ranges (cov1)
<< " is not a sub-range of containing scope."
<< std::endl;
- wr_error (wh_parent)
+ wr_message (wh_parent, mc_error)
<< "in this context: " << cov::format_ranges (cov2)
<< std::endl;
}
@@ -223,7 +223,7 @@ check_range_out_of_scope::recursively_validate
&& !cov.is_covered (start, length))
{
runoff = true;
- wr_error (wh)
+ wr_message (wh, mc_error)
<< "attribute `"
<< elfutils::dwarf::attributes::name ((*at).first)
<< "': PC range " << pri::range (start, end)
@@ -231,7 +231,7 @@ check_range_out_of_scope::recursively_validate
}
}
if (runoff)
- wr_error (wh_parent)
+ wr_message (wh_parent, mc_error)
<< "in this context: " << cov::format_ranges (cov)
<< '.' << std::endl;
}
diff --git a/dwarflint/messages.cc b/dwarflint/messages.cc
index dd8d81df..04519197 100644
--- a/dwarflint/messages.cc
+++ b/dwarflint/messages.cc
@@ -26,6 +26,7 @@
#include "messages.hh"
#include "misc.hh"
#include "coverage.hh"
+#include "option.hh"
#include <vector>
#include <sstream>
@@ -290,19 +291,81 @@ wr_message (unsigned long category, const struct where *wh,
namespace
{
class nostream: public std::ostream {};
- nostream nostr;
+ static nostream nostream;
- std::ostream &get_stream ()
+ std::ostream &
+ get_stream ()
{
return std::cout;
}
}
-static std::ostream &
-wr_warning ()
+global_opt<unsigned_option>
+ dup_threshold_opt ("Threshold for duplicate messages.",
+ "count", "dups");
+
+namespace
+{
+ unsigned
+ dup_threshold ()
+ {
+ static unsigned t = dup_threshold_opt.value ();
+ if (t == 0)
+ t = -1;
+ return t;
+ }
+}
+
+int
+message_count_filter::should_emit (void const *key)
+{
+ unsigned count = ++_m_counters[key];
+ if (count > dup_threshold ())
+ return 0;
+ else if (count == dup_threshold ())
+ return -1;
+ else
+ return 1;
+}
+
+std::ostream &
+message_context::emit (char const *str)
{
++error_count;
- return get_stream () << gettext ("warning: ");
+ std::ostream &ret = get_stream ();
+ ret << _m_prefix;
+ if (_m_where)
+ ret << *_m_where << ": ";
+ return ret << str;
+}
+
+message_context::message_context (message_count_filter *filter,
+ where const *where, char const *prefix)
+ : _m_filter (filter)
+ , _m_where (where)
+ , _m_prefix (prefix)
+{}
+
+std::ostream &
+message_context::operator << (char const *message)
+{
+ if (_m_filter == NULL)
+ return nostream;
+ else if (int status = _m_filter->should_emit (message))
+ {
+ if (status == -1)
+ get_stream () << "(threshold reached for the following message)"
+ << std::endl;
+ return emit (message);
+ }
+ else
+ return nostream;
+}
+
+std::ostream &
+message_context::operator << (std::string const &message)
+{
+ return *this << message.c_str ();
}
std::ostream &
@@ -313,36 +376,45 @@ wr_error ()
}
std::ostream &
-wr_message (message_category category)
+wr_error (where const &wh)
+{
+ return wr_error () << wh << ": ";
+}
+
+message_context
+message_context::filter_message (where const *wh, message_category category)
{
if (!message_accept (&warning_criteria, category))
- return nostr;
+ return message_context (NULL, NULL, NULL);
else if (message_accept (&error_criteria, category))
- return wr_error ();
+ return message_context (message_count_filter::inst (),
+ wh, "error: ");
else
- return wr_warning ();
+ return message_context (message_count_filter::inst (),
+ wh, "warning: ");
}
-std::ostream &
-wr_error (where const &wh)
+message_context
+wr_message (message_category category)
{
- return wr_error () << wh << ": ";
+ return message_context::filter_message (NULL, category);
}
-std::ostream &
+message_context
wr_message (where const &wh, message_category category)
{
- return wr_message (category) << wh << ": ";
+ return message_context::filter_message (&wh, category);
}
void
-wr_format_padding_message (unsigned long category,
+wr_format_padding_message (message_category category,
struct where const *wh,
uint64_t start, uint64_t end, char const *kind)
{
char msg[128];
- wr_message (category, wh, ": %s: %s.\n",
- range_fmt (msg, sizeof msg, start, end), kind);
+ wr_message (*wh, category)
+ << range_fmt (msg, sizeof msg, start, end)
+ << ": " << kind << "." << std::endl;
}
void
@@ -362,7 +434,7 @@ wr_format_leb128_message (struct where const *where,
}
void
-wr_message_padding_0 (unsigned long category,
+wr_message_padding_0 (message_category category,
struct where const *wh,
uint64_t start, uint64_t end)
{
@@ -372,7 +444,7 @@ wr_message_padding_0 (unsigned long category,
}
void
-wr_message_padding_n0 (unsigned long category,
+wr_message_padding_n0 (message_category category,
struct where const *wh,
uint64_t start, uint64_t end)
{
diff --git a/dwarflint/messages.hh b/dwarflint/messages.hh
index b4c07b8b..0efc9d36 100644
--- a/dwarflint/messages.hh
+++ b/dwarflint/messages.hh
@@ -31,6 +31,8 @@
#include <string>
#include <iosfwd>
#include <vector>
+#include <sstream>
+#include <map>
#define MESSAGE_CATEGORIES \
/* Severity: */ \
@@ -119,7 +121,7 @@ extern void wr_message (unsigned long category, const struct where *wh,
const char *format, ...)
__attribute__ ((format (printf, 3, 4)));
-extern void wr_format_padding_message (unsigned long category,
+extern void wr_format_padding_message (message_category category,
struct where const *wh,
uint64_t start, uint64_t end,
char const *kind);
@@ -130,11 +132,11 @@ extern void wr_format_leb128_message (struct where const *where,
const unsigned char *begin,
const unsigned char *end);
-extern void wr_message_padding_0 (unsigned long category,
+extern void wr_message_padding_0 (message_category category,
struct where const *wh,
uint64_t start, uint64_t end);
-extern void wr_message_padding_n0 (unsigned long category,
+extern void wr_message_padding_n0 (message_category category,
struct where const *wh,
uint64_t start, uint64_t end);
@@ -150,9 +152,66 @@ extern struct message_criteria warning_criteria;
/* Accepted (warning) messages, that are turned into errors. */
extern struct message_criteria error_criteria;
+class message_count_filter
+{
+ struct counter
+ {
+ unsigned value;
+ counter () : value (0) {}
+ unsigned operator++ () { return ++value; }
+ };
+
+ typedef std::map<void const *, counter> counters_t;
+
+ // NULL for filtered-out message, otherwise array of <key, count>
+ // pairs sorted by key.
+ counters_t _m_counters;
+
+public:
+
+ int should_emit (void const *key);
+ static message_count_filter *
+ inst ()
+ {
+ static message_count_filter inst;
+ return &inst;
+ }
+};
+
+class message_context
+{
+ message_count_filter *_m_filter;
+ where const *_m_where;
+ char const *_m_prefix;
+
+ friend message_context wr_message (where const &wh, message_category cat);
+ friend message_context wr_message (message_category cat);
+
+ std::ostream &emit (char const *str);
+
+ message_context (message_count_filter *filter,
+ where const *where, char const *prefix);
+
+public:
+ static message_context filter_message (where const *wh,
+ message_category category);
+
+ std::ostream &operator << (char const *message);
+ std::ostream &operator << (std::string const &message);
+
+ template<class T>
+ std::ostream &
+ operator << (T const &t)
+ {
+ std::stringstream ss;
+ ss << t;
+ return (*this) << ss.str ();
+ }
+};
+
std::ostream &wr_error (where const &wh);
std::ostream &wr_error ();
-std::ostream &wr_message (where const &wh, message_category cat);
-std::ostream &wr_message (message_category cat);
+message_context wr_message (where const &wh, message_category cat);
+message_context wr_message (message_category cat);
#endif//DWARFLINT_MESSAGES_HH
diff --git a/dwarflint/option.hh b/dwarflint/option.hh
index 45109a99..8016811f 100644
--- a/dwarflint/option.hh
+++ b/dwarflint/option.hh
@@ -1,5 +1,5 @@
/* Pedantic checker for DWARF files
- Copyright (C) 2010 Red Hat, Inc.
+ Copyright (C) 2010, 2011 Red Hat, Inc.
This file is part of Red Hat elfutils.
Red Hat elfutils is free software; you can redistribute it and/or modify
@@ -201,8 +201,22 @@ struct value_converter<std::string>
}
};
+template<>
+struct value_converter<unsigned>
+{
+ static unsigned convert (char const *arg)
+ {
+ unsigned u;
+ if (std::sscanf (arg, "%u", &u) == 1)
+ return u;
+ else
+ return -1;
+ }
+};
+
typedef xoption<void> void_option;
typedef xoption<std::string> string_option;
+typedef xoption<unsigned> unsigned_option;
extern options global_opts;