the DIE referring to the entry in consideration"), 0 },
{ "nohl", ARGP_nohl, NULL, 0,
N_("Don't run high-level tests"), 0 },
+ { "verbose", 'v', NULL, 0,
+ N_("Be verbose"), 0 },
{ NULL, 0, NULL, 0, NULL, 0 }
};
static void process_file (Dwarf *dwarf, const char *fname, bool only_one);
+#define REALLOC(A, BUF) \
+ do { \
+ typeof ((A)) _a = (A); \
+ if (_a->size == _a->alloc) \
+ { \
+ if (_a->alloc == 0) \
+ _a->alloc = 8; \
+ else \
+ _a->alloc *= 2; \
+ _a->BUF = xrealloc (_a->BUF, \
+ sizeof (*_a->BUF) * _a->alloc); \
+ } \
+ } while (0)
+
+struct message_term
+{
+ /* Given a term like A && !B && C && !D, we decompose it thus: */
+ enum message_category positive; /* non-zero bits for plain predicates */
+ enum message_category negative; /* non-zero bits for negated predicates */
+};
+
struct message_criteria
{
- enum message_category accept; /* cat & accept must be != 0 */
- enum message_category reject; /* cat & reject must be == 0 */
+ struct message_term *terms;
+ size_t size;
+ size_t alloc;
};
static bool
-accept_message (struct message_criteria *crit, enum message_category cat)
+message_accept (struct message_criteria *cri, enum message_category cat)
+{
+ for (size_t i = 0; i < cri->size; ++i)
+ {
+ struct message_term *t = cri->terms + i;
+ if ((t->positive & cat) == t->positive
+ && (t->negative & cat) == 0)
+ return true;
+ }
+ return false;
+}
+
+static const char *
+message_term_str (struct message_term *t)
{
- assert (crit != NULL);
- return (crit->accept & cat) != 0
- && (crit->reject & cat) == 0;
+ static char *names[] = {
+#define MC(CAT, ID) [ID] = #CAT,
+ MESSAGE_CATEGORIES
+#undef MC
+ };
+
+ unsigned max = 0;
+#define MC(CAT, ID) max = ID;
+ MESSAGE_CATEGORIES
+#undef MC
+
+ static char buf[512];
+ char *ptr = buf;
+ ptr = stpcpy (ptr, "(");
+
+ bool got = false;
+ for (unsigned i = 0; i <= max; ++i)
+ {
+ unsigned mask = 1u << i;
+ if ((t->positive & mask) != 0
+ || (t->negative & mask) != 0)
+ {
+ if (got)
+ ptr = stpcpy (ptr, " & ");
+ if ((t->negative & (1u << i)) != 0)
+ ptr = stpcpy (ptr, "~");
+ ptr = stpcpy (ptr, names[i]);
+ got = true;
+ }
+ }
+
+ if (ptr == buf + 1)
+ ptr = stpcpy (ptr, "1");
+ ptr = stpcpy (ptr, ")");
+ return buf;
}
-static struct message_criteria warning_criteria
- = {mc_all & ~(mc_strings),
- mc_pubtypes};
-static struct message_criteria error_criteria
- = {mc_impact_4 | mc_error,
- mc_none};
+static const char *
+message_cri_str (struct message_criteria *cri)
+{
+ static char buf[512];
+ char *ptr = buf;
+ *ptr = 0;
+
+ for (size_t i = 0; i < cri->size; ++i)
+ {
+ struct message_term *t = cri->terms + i;
+ if (i > 0)
+ ptr = stpcpy (ptr, " | ");
+ ptr = stpcpy (ptr, message_term_str (t));
+ }
+
+ return buf;
+}
+
+static void
+message_cri_and (struct message_criteria *cri, struct message_term term)
+{
+ assert ((term.positive & term.negative) == 0);
+ //printf ("message_cri_and(%s)\n : %s\n", message_term_str (&term), message_cri_str (cri));
+ for (size_t i = 0; i < cri->size; )
+ {
+ struct message_term *t = cri->terms + i;
+ //struct message_term orig = *t;
+ t->positive |= term.positive;
+ t->negative |= term.negative;
+ if ((t->positive & t->negative) != 0)
+ {
+ /* A ^ ~A -> drop the term. */
+ /*
+ printf ("(eliminate %s)\n", message_term_str (&orig));
+ printf ("(became %s)\n", message_term_str (t));
+ */
+ cri->terms[i] = cri->terms[--cri->size];
+ }
+ else
+ ++i;
+ }
+ //printf (" : %s\n", message_cri_str (cri));
+}
+
+static void
+message_cri_or (struct message_criteria *cri, struct message_term term)
+{
+ assert ((term.positive & term.negative) == 0);
+ //printf ("message_cri_or(%s)\n : %s\n", message_term_str (&term), message_cri_str (cri));
+ REALLOC (cri, terms);
+ cri->terms[cri->size++] = term;
+ //printf (" : %s\n", message_cri_str (cri));
+}
+
+
+/* Messages that are accepted (and made into warning). */
+static struct message_criteria warning_criteria;
+
+/* Accepted (warning) messages, that are turned into errors. */
+static struct message_criteria error_criteria;
+
static unsigned error_count = 0;
static bool
check_category (enum message_category cat)
{
- return accept_message (&warning_criteria, cat);
+ return message_accept (&warning_criteria, cat);
}
static void
{
va_list ap;
va_start (ap, format);
- if (accept_message (&warning_criteria, category))
+ if (message_accept (&warning_criteria, category))
{
- if (accept_message (&error_criteria, category))
+ if (message_accept (&error_criteria, category))
wr_verror (wh, format, ap);
else
wr_vwarning (wh, format, ap);
}
/* True if no message is to be printed if the run is succesful. */
-static bool be_quiet;
+static bool be_quiet = false; /* -q */
+static bool be_verbose = false; /* -v */
static bool be_strict = false; /* --strict */
static bool be_gnu = false; /* --gnu */
static bool be_tolerant = false; /* --tolerant */
int remaining;
argp_parse (&argp, argc, argv, 0, &remaining, NULL);
+ /* Initialize warning & error criteria. */
+ message_cri_or (&error_criteria,
+ (struct message_term){mc_impact_4, mc_none});
+ message_cri_or (&error_criteria,
+ (struct message_term){mc_error, mc_none});
+
+ message_cri_or (&warning_criteria,
+ (struct message_term){mc_none, mc_strings});
+
+ /* Configure warning & error criteria according to configuration. */
if (tolerate_nodebug)
- warning_criteria.reject |= mc_elf;
+ message_cri_and (&warning_criteria,
+ (struct message_term){mc_none, mc_elf});
+
if (be_gnu)
- warning_criteria.reject |= mc_acc_bloat | mc_pubtypes;
- if (be_strict)
{
- warning_criteria.accept |= mc_strings;
- if (!be_gnu)
- warning_criteria.reject &= ~mc_pubtypes;
+ message_cri_and (&warning_criteria,
+ (struct message_term){mc_none, mc_acc_bloat});
+ if (!be_strict)
+ message_cri_and (&warning_criteria,
+ (struct message_term){mc_none, mc_pubtypes});
}
+
+ if (be_strict)
+ message_cri_and (&warning_criteria,
+ (struct message_term){mc_strings, mc_none});
+
if (be_tolerant)
- warning_criteria.reject |= mc_loc | mc_ranges;
+ {
+ message_cri_and (&warning_criteria,
+ (struct message_term){mc_none, mc_loc});
+ message_cri_and (&warning_criteria,
+ (struct message_term){mc_none, mc_ranges});
+ }
+
+ if (be_verbose)
+ {
+ printf ("warning criteria: %s\n", message_cri_str (&warning_criteria));
+ printf ("error criteria: %s\n", message_cri_str (&error_criteria));
+ }
/* Before we start tell the ELF library which version we are using. */
elf_version (EV_CURRENT);
case 'q':
be_quiet = true;
+ be_verbose = false;
+ break;
+
+ case 'v':
+ be_quiet = false;
+ be_verbose = true;
break;
case ARGP_KEY_NO_ARGS:
return 0;
}
-#define REALLOC(A, BUF) \
- do { \
- typeof ((A)) _a = (A); \
- if (_a->size == _a->alloc) \
- { \
- if (_a->alloc == 0) \
- _a->alloc = 8; \
- else \
- _a->alloc *= 2; \
- _a->BUF = xrealloc (_a->BUF, \
- sizeof (*_a->BUF) * _a->alloc); \
- } \
- } while (0)
-
#define PRI_CU "CU 0x%" PRIx64
#define PRI_DIE "DIE 0x%" PRIx64
#define PRI_NOT_ENOUGH ": not enough data for %s.\n"
for (size_t i = 0; i < include_directories.size; ++i)
if (!include_directories.dirs[i].used)
- wr_message (mc_impact_3 | mc_acc_bloat | mc_line, &where,
- ": the include #%zd `%s' is not used.\n",
+ wr_message (mc_impact_3 | mc_acc_bloat | mc_line,
+ &where, ": the include #%zd `%s' is not used.\n",
i + 1, include_directories.dirs[i].name);
for (size_t i = 0; i < files.size; ++i)
if (!files.files[i].used)
- wr_message (mc_impact_3 | mc_acc_bloat | mc_line, &where,
- ": the file #%zd `%s' is not used.\n",
+ wr_message (mc_impact_3 | mc_acc_bloat | mc_line,
+ &where, ": the file #%zd `%s' is not used.\n",
i + 1, files.files[i].name);
if (!terminated)
/* Functions and data structures for emitting various types of
messages. */
+#define MESSAGE_CATEGORIES \
+ /* Severity: */ \
+ MC (impact_1, 0) /* no impact on the consumer */ \
+ MC (impact_2, 1) /* still no impact, but suspicious or worth mentioning */ \
+ MC (impact_3, 2) /* some impact */ \
+ MC (impact_4, 3) /* high impact */ \
+ \
+ /* Accuracy: */ \
+ MC (acc_bloat, 4) /* unnecessary constructs (e.g. unreferenced strings) */ \
+ MC (acc_suboptimal, 5) /* suboptimal construct (e.g. lack of siblings) */ \
+ \
+ /* Various: */ \
+ MC (error, 6) /* turn the message into an error */ \
+ \
+ /* Area: */ \
+ MC (leb128, 7) /* ULEB/SLEB storage */ \
+ MC (abbrevs, 8) /* abbreviations and abbreviation tables */ \
+ MC (die_rel, 9) /* DIE relationship */ \
+ MC (die_other, 10) /* other messages related to DIEs */ \
+ MC (info, 11) /* messages related to .debug_info, but not particular DIEs */ \
+ MC (strings, 12) /* string table */ \
+ MC (aranges, 13) /* address ranges table */ \
+ MC (elf, 14) /* ELF structure, e.g. missing optional sections */ \
+ MC (pubtables, 15) /* table of public names/types */ \
+ MC (pubtypes, 16) /* .debug_pubtypes presence */ \
+ MC (loc, 17) /* messages related to .debug_loc */ \
+ MC (ranges, 18) /* messages related to .debug_ranges */ \
+ MC (line, 19) /* messages related to .debug_line */ \
+ MC (reloc, 20) /* messages related to relocation handling */ \
+ MC (header, 21) /* messages related to header portions in general */ \
+ MC (other, 31) /* messages unrelated to any of the above */
+
enum message_category
{
mc_none = 0,
- /* Severity: */
- mc_impact_1 = 0x1, // no impact on the consumer
- mc_impact_2 = 0x2, // still no impact, but suspicious or worth mentioning
- mc_impact_3 = 0x4, // some impact
- mc_impact_4 = 0x8, // high impact
- mc_impact_all= 0xf, // all severity levels
- mc_impact_2p = 0xe, // 2+
- mc_impact_3p = 0xc, // 3+
-
- /* Accuracy: */
- mc_acc_bloat = 0x10, // unnecessary constructs (e.g. unreferenced strings)
- mc_acc_suboptimal= 0x20, // suboptimal construct (e.g. lack of siblings)
- mc_acc_all = 0x30, // all accuracy options
-
- /* Various: */
- mc_error = 0x40, // turn the message into an error
-
- /* Area: */
- mc_leb128 = 0x100, // ULEB/SLEB storage
- mc_abbrevs = 0x200, // abbreviations and abbreviation tables
- mc_die_rel = 0x400, // DIE relationship
- mc_die_other = 0x800, // other messages related to DIEs
- mc_info = 0x1000, // messages related to .debug_info, but not particular DIEs
- mc_strings = 0x2000, // string table
- mc_aranges = 0x4000, // address ranges table
- mc_elf = 0x8000, // ELF structure, e.g. missing optional sections
- mc_pubtables = 0x10000, // table of public names/types
- mc_pubtypes = 0x20000, // .debug_pubtypes presence
- mc_loc = 0x40000, // messages related to .debug_loc
- mc_ranges = 0x80000, // messages related to .debug_ranges
- mc_line = 0x1000000, // messages related to .debug_line
- mc_reloc = 0x40000000, // messages related to relocation handling
- mc_other = 0x80000000, // messages unrelated to any of the above
- mc_all = 0xffffff00, // all areas
+#define MC(CAT, ID)\
+ mc_##CAT = 1u << ID,
+ MESSAGE_CATEGORIES
+#undef MC
};
extern void wr_error (const struct where *wh, const char *format, ...)