]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
dwarflint: Add filtering of duplicate messages
authorPetr Machata <pmachata@redhat.com>
Mon, 28 Mar 2011 22:54:48 +0000 (00:54 +0200)
committerPetr Machata <pmachata@redhat.com>
Mon, 28 Mar 2011 22:54:48 +0000 (00:54 +0200)
- 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.

dwarflint/check_debug_aranges.cc
dwarflint/check_debug_loc_range.cc
dwarflint/check_matching_ranges.cc
dwarflint/check_range_out_of_scope.cc
dwarflint/messages.cc
dwarflint/messages.hh
dwarflint/option.hh

index b0c84e149e551653cdbd84e5576cac4ad60bfe33..0d3e3b30986793b0cf77f77b9c80581f550fa35d 100644 (file)
@@ -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);
index cdd696062e113c5f0e7f6f3e741c669c98b31c51..f87b2aa474715e9bfbb488248444e725bda5b448 100644 (file)
@@ -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;
          }
 
index af46ffffea1339c1415538cd43678ec217e00a34..a567ce48f556488a599846996ec4d05cbf2b532c 100644 (file)
@@ -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
index 016cb38acbb781fcfad15ace18286e3de082c3cb..daa2bc3d1bc355f271414bf6971385a1ef414836 100644 (file)
@@ -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;
            }
index dd8d81dfab9cd166e01b046de6511f693ed57166..04519197c495d5b3164eb263c5fcad26b3406655 100644 (file)
@@ -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)
 {
index b4c07b8b3cd2d0b1d6e1dbad24877ff92e86e145..0efc9d360e85de58cb367e174f849d18566079f3 100644 (file)
@@ -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
index 45109a992001235654d37839d31f2e6fde935d07..8016811fc626b70479d9cafb555988f9b16b2812 100644 (file)
@@ -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;