]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
dwarflint: Better message filtering system
authorPetr Machata <pmachata@redhat.com>
Thu, 5 Mar 2009 16:22:45 +0000 (17:22 +0100)
committerPetr Machata <pmachata@redhat.com>
Thu, 5 Mar 2009 16:22:45 +0000 (17:22 +0100)
src/dwarflint.c
src/dwarflint.h

index 1a632f9cb148126714e2e5e52485c82c58281753..04295cd65cb505cb3c4cff60f24bd71ed7a3fb40 100644 (file)
@@ -81,6 +81,8 @@ broken in certain ways"), 0 },
 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 }
 };
 
@@ -105,32 +107,154 @@ static bool tolerate_nodebug = false;
 
 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
@@ -175,9 +299,9 @@ wr_message (enum message_category category, const struct where *wh,
 {
   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);
@@ -230,7 +354,8 @@ wr_message_padding_n0 (enum message_category category,
 }
 
 /* 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 */
@@ -250,18 +375,46 @@ main (int argc, char *argv[])
   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);
@@ -354,6 +507,12 @@ parse_opt (int key, char *arg __attribute__ ((unused)),
 
     case 'q':
       be_quiet = true;
+      be_verbose = false;
+      break;
+
+    case 'v':
+      be_quiet = false;
+      be_verbose = true;
       break;
 
     case ARGP_KEY_NO_ARGS:
@@ -368,20 +527,6 @@ parse_opt (int key, char *arg __attribute__ ((unused)),
   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"
@@ -4898,14 +5043,14 @@ check_line_structural (struct section_data *data,
 
       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)
index 335226755a61aaa181642f65c47756d2bd5f1284..2c6bc70734e534c05d54e9206ce30e18e80744a8 100644 (file)
@@ -74,44 +74,46 @@ extern "C"
   /* 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, ...)