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)
{
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);
&& 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;
}
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 (),
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
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;
}
&& !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)
}
}
if (runoff)
- wr_error (wh_parent)
+ wr_message (wh_parent, mc_error)
<< "in this context: " << cov::format_ranges (cov)
<< '.' << std::endl;
}
#include "messages.hh"
#include "misc.hh"
#include "coverage.hh"
+#include "option.hh"
#include <vector>
#include <sstream>
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 &
}
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
}
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)
{
}
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)
{
#include <string>
#include <iosfwd>
#include <vector>
+#include <sstream>
+#include <map>
#define MESSAGE_CATEGORIES \
/* Severity: */ \
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);
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);
/* 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
/* 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
}
};
+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;