]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
dwarflint: Dissect dwarflint.c to modules
authorPetr Machata <pmachata@redhat.com>
Thu, 8 Oct 2009 18:00:15 +0000 (20:00 +0200)
committerPetr Machata <pmachata@redhat.com>
Wed, 18 Aug 2010 12:55:11 +0000 (14:55 +0200)
src/Makefile.am
src/dwarflint-coverage.cc
src/dwarflint-coverage.h
src/dwarflint-hl.cc
src/dwarflint-main.cc [new file with mode: 0644]
src/dwarflint-messages.cc [new file with mode: 0644]
src/dwarflint-messages.h [new file with mode: 0644]
src/dwarflint-misc.h [new file with mode: 0644]
src/dwarflint-where.h [new file with mode: 0644]
src/dwarflint.c
src/dwarflint.h

index 30bc3c3649ef08abafdd1822ba0e82c98e0457f4..87ece19375a149b3d4d0a57d38851dfaf50ccc6c 100644 (file)
@@ -78,10 +78,13 @@ dwarfcmp_test_CPPFLAGS = -DTEST
 dwarfcmp_test_SOURCES = $(dwarfcmp_SOURCES)
 dwarfcmp_test_LDADD = $(dwarfcmp_LDADD)
 
-dwarflint_SOURCES = dwarflint.c dwarflint.h dwarflint-hl.cc \
-                   dwarflint-expected-at.cc dwarflint-expected.hh \
-                   dwarfstrings.c dwarflint-coverage.c dwarflint-coverage.h \
-                   dwarflint-readctx.c dwarflint-readctx.h
+dwarflint_SOURCES = dwarfstrings.c \
+                   dwarflint-main.cc dwarflint.h dwarflint-misc.h \
+                   dwarflint.c \
+                   dwarflint-hl.cc dwarflint-expected-at.cc dwarflint-expected.hh \
+                   dwarflint-coverage.cc dwarflint-coverage.h \
+                   dwarflint-readctx.c  dwarflint-readctx.h \
+                   dwarflint-messages.cc dwarflint-messages.h dwarflint-where.h
 
 readelf_SOURCES = readelf.c dwarfstrings.c
 
index 4e456029244241bedef5c7a8160da51a1bcf00dc..fee57a15891e17217c277c9d1ad4ab1a872239e2 100644 (file)
 #endif
 
 #include "dwarflint-coverage.hh"
-extern "C"
-{
-#include "../lib/system.h"
-}
 
 #include <stdbool.h>
 #include <assert.h>
index f21c55b190e03caf5e01066469181a565b134bab..28d86dd5d9376e650dcad22c8cec83e2fd26240d 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
-#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 = (typeof (_a->BUF))                            \
-         xrealloc (_a->BUF,                                    \
-                   sizeof (*_a->BUF) * _a->alloc);             \
-      }                                                                \
-  } while (0)
-
-#define WIPE(OBJ) memset (&OBJ, 0, sizeof (OBJ))
+#include "dwarflint-misc.h"
 
 #ifdef __cplusplus
-# define IF_CPLUSPLUS(X) X
 extern "C"
 {
 #endif
@@ -122,8 +106,9 @@ bool coverage_find_ranges (struct coverage const *cov,
                          void *data);
 
 #ifdef __cplusplus
-# define IF_CPLUSPLUS(X) X
 }
+
+std::string range_fmt (uint64_t start, uint64_t end);
 #endif
 
 #endif//DWARFLINT_COVERAGE_H
index d01acd757301bbd62f6f1cbe3e7141e74f73d352..9e7d16998c0c782b63e066233072c32c86929308 100644 (file)
@@ -1,4 +1,4 @@
-/* Pedantic checking of DWARF files.
+/* Pedantic checking of DWARF files.  High level checks.
    Copyright (C) 2009 Red Hat, Inc.
    This file is part of Red Hat elfutils.
    Written by Petr Machata <pmachata@redhat.com>, 2009.
 
 using namespace elfutils;
 
-namespace
-{
-  message_category cat (message_category c1,
-                       message_category c2,
-                       message_category c3 = mc_none)
-  {
-    return static_cast<message_category> (c1 | c2 | c3);
-  }
-}
-
 class hl_ctx
 {
   Dwarf *handle;
diff --git a/src/dwarflint-main.cc b/src/dwarflint-main.cc
new file mode 100644 (file)
index 0000000..a9ecc20
--- /dev/null
@@ -0,0 +1,362 @@
+/* Pedantic checking of DWARF files.  Low-level checks.
+   Copyright (C) 2008,2009 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <argp.h>
+#include <libintl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <error.h>
+
+#include <iostream>
+
+#include "dwarflint.h"
+
+/* Bug report address.  */
+const char *argp_program_bug_address = PACKAGE_BUGREPORT;
+
+#define ARGP_strict    300
+#define ARGP_gnu       301
+#define ARGP_tolerant  302
+#define ARGP_ref        303
+#define ARGP_nohl       304
+#define ARGP_dump_off   305
+
+/* Definitions of arguments for argp functions.  */
+static const struct argp_option options[] =
+{
+  { "strict", ARGP_strict, NULL, 0,
+    N_("Be extremely strict, flag level 2 features."), 0 },
+  { "quiet", 'q', NULL, 0, N_("Do not print anything if successful"), 0 },
+  { "ignore-missing", 'i', NULL, 0,
+    N_("Don't complain if files have no DWARF at all"), 0 },
+  { "gnu", ARGP_gnu, NULL, 0,
+    N_("Binary has been created with GNU toolchain and is therefore known to be \
+broken in certain ways"), 0 },
+  { "tolerant", ARGP_tolerant, NULL, 0,
+    N_("Don't output certain common error messages"), 0 },
+  { "ref", ARGP_ref, NULL, 0,
+    N_("When validating .debug_loc and .debug_ranges, display information about \
+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 },
+  { "dump-offsets", ARGP_dump_off, NULL, 0,
+    N_("Dump DIE offsets to stderr as the tree is iterated."), 0 },
+  { NULL, 0, NULL, 0, NULL, 0 }
+};
+
+/* Short description of program.  */
+static const char doc[] = N_("\
+Pedantic checking of DWARF stored in ELF files.");
+
+/* Strings for arguments in help texts.  */
+static const char args_doc[] = N_("FILE...");
+
+/* If true, we accept silently files without debuginfo.  */
+bool tolerate_nodebug = false;
+
+/* True if no message is to be printed if the run is succesful.  */
+bool be_quiet = false; /* -q */
+bool be_verbose = false; /* -v */
+bool be_strict = false; /* --strict */
+bool be_gnu = false; /* --gnu */
+bool be_tolerant = false; /* --tolerant */
+bool show_refs = false; /* --ref */
+bool do_high_level = true; /* ! --nohl */
+bool dump_die_offsets = false; /* --dump-offsets */
+
+/* Messages that are accepted (and made into warning).  */
+struct message_criteria warning_criteria;
+
+/* Accepted (warning) messages, that are turned into errors.  */
+struct message_criteria error_criteria;
+
+
+static error_t parse_opt (int key, char *arg, struct argp_state *state);
+
+/* Data structure to communicate with argp functions.  */
+static struct argp argp =
+{
+  options, parse_opt, args_doc, doc, NULL, NULL, NULL
+};
+
+/* Handle program arguments.  */
+static error_t
+parse_opt (int key, char *arg __attribute__ ((unused)),
+          struct argp_state *state __attribute__ ((unused)))
+{
+  switch (key)
+    {
+    case ARGP_strict:
+      be_strict = true;
+      break;
+
+    case ARGP_gnu:
+      be_gnu = true;
+      break;
+
+    case ARGP_tolerant:
+      be_tolerant = true;
+      break;
+
+    case ARGP_ref:
+      show_refs = true;
+      break;
+
+    case ARGP_nohl:
+      do_high_level = false;
+      break;
+
+    case ARGP_dump_off:
+      dump_die_offsets = true;
+      break;
+
+    case 'i':
+      tolerate_nodebug = true;
+      break;
+
+    case 'q':
+      be_quiet = true;
+      be_verbose = false;
+      break;
+
+    case 'v':
+      be_quiet = false;
+      be_verbose = true;
+      break;
+
+    case ARGP_KEY_NO_ARGS:
+      fputs (gettext ("Missing file name.\n"), stderr);
+      argp_help (&argp, stderr, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR,
+                program_invocation_short_name);
+      exit (1);
+
+    default:
+      return ARGP_ERR_UNKNOWN;
+    }
+  return 0;
+}
+
+static int
+layout_rel_file (Elf *elf)
+{
+  GElf_Ehdr ehdr;
+  if (gelf_getehdr (elf, &ehdr) == NULL)
+    return 1;
+
+  if (ehdr.e_type != ET_REL)
+    return 0;
+
+  /* Taken from libdwfl. */
+  GElf_Addr base = 0;
+  GElf_Addr start = 0, end = 0, bias = 0;
+
+  bool first = true;
+  Elf_Scn *scn = NULL;
+  while ((scn = elf_nextscn (elf, scn)) != NULL)
+    {
+      GElf_Shdr shdr_mem;
+      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+      if (unlikely (shdr == NULL))
+       return 1;
+
+      if (shdr->sh_flags & SHF_ALLOC)
+       {
+         const GElf_Xword align = shdr->sh_addralign ?: 1;
+         const GElf_Addr next = (end + align - 1) & -align;
+         if (shdr->sh_addr == 0
+             /* Once we've started doing layout we have to do it all,
+                unless we just layed out the first section at 0 when
+                it already was at 0.  */
+             || (bias == 0 && end > start && end != next))
+           {
+             shdr->sh_addr = next;
+             if (end == base)
+               /* This is the first section assigned a location.
+                  Use its aligned address as the module's base.  */
+               start = base = shdr->sh_addr;
+             else if (unlikely (base & (align - 1)))
+               {
+                 /* If BASE has less than the maximum alignment of
+                    any section, we eat more than the optimal amount
+                    of padding and so make the module's apparent
+                    size come out larger than it would when placed
+                    at zero.  So reset the layout with a better base.  */
+
+                 start = end = base = (base + align - 1) & -align;
+                 Elf_Scn *prev_scn = NULL;
+                 do
+                   {
+                     prev_scn = elf_nextscn (elf, prev_scn);
+                     GElf_Shdr prev_shdr_mem;
+                     GElf_Shdr *prev_shdr = gelf_getshdr (prev_scn,
+                                                          &prev_shdr_mem);
+                     if (unlikely (prev_shdr == NULL))
+                       return 1;
+                     if (prev_shdr->sh_flags & SHF_ALLOC)
+                       {
+                         const GElf_Xword prev_align
+                           = prev_shdr->sh_addralign ?: 1;
+
+                         prev_shdr->sh_addr
+                           = (end + prev_align - 1) & -prev_align;
+                         end = prev_shdr->sh_addr + prev_shdr->sh_size;
+
+                         if (unlikely (! gelf_update_shdr (prev_scn,
+                                                           prev_shdr)))
+                           return 1;
+                       }
+                   }
+                 while (prev_scn != scn);
+                 continue;
+               }
+
+             end = shdr->sh_addr + shdr->sh_size;
+             if (likely (shdr->sh_addr != 0)
+                 && unlikely (! gelf_update_shdr (scn, shdr)))
+               return 1;
+           }
+         else
+           {
+             /* The address is already assigned.  Just track it.  */
+             if (first || end < shdr->sh_addr + shdr->sh_size)
+               end = shdr->sh_addr + shdr->sh_size;
+             if (first || bias > shdr->sh_addr)
+               /* This is the lowest address in the module.  */
+               bias = shdr->sh_addr;
+
+             if ((shdr->sh_addr - bias + base) & (align - 1))
+               /* This section winds up misaligned using BASE.
+                  Adjust BASE upwards to make it congruent to
+                  the lowest section address in the file modulo ALIGN.  */
+               base = (((base + align - 1) & -align)
+                       + (bias & (align - 1)));
+           }
+
+         first = false;
+       }
+    }
+  return 0;
+}
+
+int
+main (int argc, char *argv[])
+{
+  /* Set locale.  */
+  setlocale (LC_ALL, "");
+
+  /* Initialize the message catalog.  */
+  textdomain (PACKAGE_TARNAME);
+
+  /* Parse and process arguments.  */
+  int remaining;
+  argp_parse (&argp, argc, argv, 0, &remaining, NULL);
+
+  /* Initialize warning & error criteria.  */
+  warning_criteria |= message_term (mc_none, mc_none);
+
+  error_criteria |= message_term (mc_impact_4, mc_none);
+  error_criteria |= message_term (mc_error, mc_none);
+
+  /* Configure warning & error criteria according to configuration.  */
+  if (tolerate_nodebug)
+    warning_criteria &= message_term (mc_none, mc_elf);
+
+  if (be_gnu)
+    warning_criteria &= message_term (mc_none, mc_acc_bloat);
+
+  if (!be_strict)
+    {
+      warning_criteria &= message_term (mc_none, mc_strings);
+      warning_criteria
+       &= message_term (cat (mc_line, mc_header, mc_acc_bloat), mc_none);
+      warning_criteria &= message_term (mc_none, mc_pubtypes);
+    }
+
+  if (be_tolerant)
+    {
+      warning_criteria &= message_term (mc_none, mc_loc);
+      warning_criteria &= message_term (mc_none, mc_ranges);
+    }
+
+  if (be_verbose)
+    {
+      std::cout << "warning criteria: " << warning_criteria.str () << std::endl;
+      std::cout << "error criteria:   " << error_criteria.str () << std::endl;
+    }
+
+  /* Before we start tell the ELF library which version we are using.  */
+  elf_version (EV_CURRENT);
+
+  /* Now process all the files given at the command line.  */
+  bool only_one = remaining + 1 == argc;
+  do
+    {
+      /* Open the file.  */
+      int fd = open (argv[remaining], O_RDONLY);
+      if (fd == -1)
+       {
+         error (0, errno, gettext ("cannot open input file"));
+         continue;
+       }
+
+      /* Create an `Elf' descriptor.  */
+      Elf *elf = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL);
+      if (elf == NULL)
+      invalid_elf:
+       wr_error (NULL,
+                 gettext ("Error processing ELF file: %s\n"),
+                 elf_errmsg (-1));
+      else
+       {
+         unsigned int prev_error_count = error_count;
+         if (layout_rel_file (elf))
+           goto invalid_elf;
+
+         process_file (elf, argv[remaining], only_one);
+
+         elf_errno (); /* Clear errno.  */
+         elf_end (elf);
+         int err = elf_errno ();
+         if (err != 0)
+           wr_error (NULL,
+                     gettext ("error while closing Elf descriptor: %s\n"),
+                     elf_errmsg (err));
+
+         if (prev_error_count == error_count && !be_quiet)
+           puts (gettext ("No errors"));
+       }
+
+      close (fd);
+    }
+  while (++remaining < argc);
+
+  return error_count != 0;
+}
diff --git a/src/dwarflint-messages.cc b/src/dwarflint-messages.cc
new file mode 100644 (file)
index 0000000..9539e64
--- /dev/null
@@ -0,0 +1,269 @@
+#include "dwarflint-messages.h"
+#include "dwarflint-misc.h"
+#include "dwarflint-coverage.h"
+
+#include <vector>
+#include <sstream>
+#include <cassert>
+#include <cstdarg>
+
+unsigned error_count = 0;
+
+bool
+message_accept (struct message_criteria const *cri,
+               unsigned long 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;
+}
+
+namespace
+{
+  struct cat_to_str
+    : public std::vector<std::string>
+  {
+    cat_to_str ()
+    {
+#define MC(CAT, ID)  {reserve (ID); (*this)[ID] = #CAT;}
+      MESSAGE_CATEGORIES
+#undef MC
+    }
+  };
+}
+
+std::string
+message_term::str () const
+{
+  static cat_to_str names;
+  static size_t max = names.size ();
+
+  std::ostringstream os;
+  os << '(';
+
+  bool got = false;
+  for (size_t i = 0; i <= max; ++i)
+    {
+      size_t mask = 1u << i;
+      if ((positive & mask) != 0
+         || (negative & mask) != 0)
+       {
+         if (got)
+           os << " & ";
+         if ((negative & (1u << i)) != 0)
+           os << '~';
+         os << names[i];
+         got = true;
+       }
+    }
+
+  if (!got)
+    os << '1';
+
+  os << ')';
+  return os.str ();
+}
+
+std::string
+message_criteria::str () const
+{
+  std::ostringstream os;
+
+  for (size_t i = 0; i < size; ++i)
+    {
+      message_term const &t = terms[i];
+      if (i > 0)
+       os << " | ";
+      os << t.str ();
+    }
+
+  return os.str ();
+}
+
+void
+message_criteria::operator &= (message_term const &term)
+{
+  assert ((term.positive & term.negative) == 0);
+  for (size_t i = 0; i < size; )
+    {
+      message_term &t = terms[i];
+      t.positive |= term.positive;
+      t.negative |= term.negative;
+      if ((t.positive & t.negative) != 0)
+       /* A ^ ~A -> drop the term.  */
+       terms[i] = terms[--size];
+      else
+       ++i;
+    }
+}
+
+void
+message_criteria::operator |= (message_term const &term)
+{
+  assert ((term.positive & term.negative) == 0);
+  REALLOC (this, terms);
+  terms[size++] = term;
+}
+
+// xxx this one is inaccessible from the outside.  Make it like &=, |=
+// above
+/* NEG(a&b&~c) -> (~a + ~b + c) */
+message_criteria
+operator ! (message_term const &term)
+{
+  assert ((term.positive & term.negative) == 0);
+
+  unsigned max = 0;
+#define MC(CAT, ID) max = ID;
+  MESSAGE_CATEGORIES
+#undef MC
+
+  message_criteria ret;
+  for (size_t i = 0; i < max; ++i)
+    {
+      unsigned mask = 1u << i;
+      if ((term.positive & mask) != 0)
+       ret |= message_term (1u << i, mc_none);
+      else if ((term.negative & mask) != 0)
+       ret |= message_term (mc_none, 1u << i);
+    }
+
+  return ret;
+}
+
+// xxx this one is inaccessible from the outside.  Make it like &=, |=
+// above
+/* MUL((a&b + c&d), (e&f + g&h)) -> (a&b&e&f + a&b&g&h + c&d&e&f + c&d&g&h) */
+void
+message_cri_mul (struct message_criteria *cri, struct message_criteria *rhs)
+{
+  struct message_criteria ret;
+  WIPE (ret);
+
+  for (size_t i = 0; i < cri->size; ++i)
+    for (size_t j = 0; j < rhs->size; ++j)
+      {
+       struct message_term t1 = cri->terms[i];
+       struct message_term *t2 = rhs->terms + j;
+       t1.positive |= t2->positive;
+       t1.negative |= t2->negative;
+       if (t1.positive & t1.negative)
+         /* A ^ ~A -> drop the term.  */
+         continue;
+       ret |= t1;
+      }
+
+  free (cri->terms);
+  *cri = ret;
+}
+
+// xxx this one is inaccessible from the outside.  Bind it properly
+/* Reject message if TERM passes.  */
+void
+message_cri_and_not (message_criteria &cri, message_term const &term)
+{
+  message_criteria tmp = !message_term (term.negative, term.positive);
+  message_cri_mul (&cri, &tmp);
+}
+
+static void
+wr_verror (const struct where *wh, const char *format, va_list ap)
+{
+  printf ("error: %s", where_fmt (wh, NULL));
+  vprintf (format, ap);
+  where_fmt_chain (wh, "error");
+  ++error_count;
+}
+
+static void
+wr_vwarning (const struct where *wh, const char *format, va_list ap)
+{
+  printf ("warning: %s", where_fmt (wh, NULL));
+  vprintf (format, ap);
+  where_fmt_chain (wh, "warning");
+  ++error_count;
+}
+
+void
+wr_error (const struct where *wh, const char *format, ...)
+{
+  va_list ap;
+  va_start (ap, format);
+  wr_verror (wh, format, ap);
+  va_end (ap);
+}
+
+void
+wr_warning (const struct where *wh, const char *format, ...)
+{
+  va_list ap;
+  va_start (ap, format);
+  wr_vwarning (wh, format, ap);
+  va_end (ap);
+}
+
+void
+wr_message (unsigned long category, const struct where *wh,
+           const char *format, ...)
+{
+  va_list ap;
+  va_start (ap, format);
+  if (message_accept (&warning_criteria, category))
+    {
+      if (message_accept (&error_criteria, category))
+       wr_verror (wh, format, ap);
+      else
+       wr_vwarning (wh, format, ap);
+    }
+  va_end (ap);
+}
+
+void
+wr_format_padding_message (unsigned long category,
+                          struct where *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);
+}
+
+void
+wr_format_leb128_message (struct where *where, const char *what,
+                         const char *purpose,
+                         const unsigned char *begin, const unsigned char *end)
+{
+  unsigned long category = mc_leb128 | mc_acc_bloat | mc_impact_3;
+  char buf[(end - begin) * 3 + 1]; // 2 hexa digits+" " per byte, and term. 0
+  char *ptr = buf;
+  for (; begin < end; ++begin)
+    ptr += sprintf (ptr, " %02x", *begin);
+  wr_message (category, where,
+             ": %s: value %s encoded as `%s'.\n",
+             what, purpose, buf + 1);
+}
+
+void
+wr_message_padding_0 (unsigned long category,
+                     struct where *wh,
+                     uint64_t start, uint64_t end)
+{
+  wr_format_padding_message (category | mc_acc_bloat | mc_impact_1,
+                            wh, start, end,
+                            "unnecessary padding with zero bytes");
+}
+
+void
+wr_message_padding_n0 (unsigned long category,
+                      struct where *wh,
+                      uint64_t start, uint64_t end)
+{
+  wr_format_padding_message (category | mc_acc_bloat | mc_impact_1,
+                            wh, start, end,
+                            "unreferenced non-zero bytes");
+}
diff --git a/src/dwarflint-messages.h b/src/dwarflint-messages.h
new file mode 100644 (file)
index 0000000..3ae7c16
--- /dev/null
@@ -0,0 +1,148 @@
+#ifndef DWARFLINT_MESSAGES_H
+#define DWARFLINT_MESSAGES_H
+
+#include "dwarflint-where.h"
+
+#ifdef __cplusplus
+# define IF_CPLUSPLUS(X) X
+# include <string>
+extern "C"
+{
+#endif
+
+#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,
+
+#define MC(CAT, ID)\
+    mc_##CAT = 1u << ID,
+    MESSAGE_CATEGORIES
+#undef MC
+  };
+
+  struct message_term
+  {
+    /* Given a term like A && !B && C && !D, we decompose it thus: */
+    unsigned long positive; /* non-zero bits for plain predicates */
+    unsigned long negative; /* non-zero bits for negated predicates */
+
+#ifdef __cplusplus
+    message_term (unsigned long pos, unsigned long neg)
+      : positive (pos), negative (neg)
+    {}
+    std::string str () const;
+#endif
+  };
+
+  struct message_criteria
+  {
+    struct message_term *terms;
+    size_t size;
+    size_t alloc;
+
+#ifdef __cplusplus
+    message_criteria ()
+      : terms (NULL), size (0), alloc (0)
+    {}
+    ~message_criteria ()
+    {
+      free (terms);
+    }
+
+    void operator |= (message_term const &term);
+    void operator &= (message_term const &term);
+    std::string str () const;
+#endif
+  };
+
+#ifdef __cplusplus
+  message_criteria operator ! (message_term const &);
+#endif
+
+  extern void wr_error (const struct where *wh, const char *format, ...)
+    __attribute__ ((format (printf, 2, 3)));
+
+  extern void wr_warning (const struct where *wh, const char *format, ...)
+    __attribute__ ((format (printf, 2, 3)));
+
+  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,
+                                        struct where *wh,
+                                        uint64_t start, uint64_t end,
+                                        char const *kind);
+
+  extern void wr_format_leb128_message (struct where *where, const char *what,
+                                       const char *purpose,
+                                       const unsigned char *begin,
+                                       const unsigned char *end);
+
+  extern void wr_message_padding_0 (unsigned long category,
+                                   struct where *wh,
+                                   uint64_t start, uint64_t end);
+
+  extern void wr_message_padding_n0 (unsigned long category,
+                                    struct where *wh,
+                                    uint64_t start, uint64_t end);
+
+  extern bool message_accept (struct message_criteria const *cri,
+                             unsigned long cat);
+
+
+  extern unsigned error_count;
+
+  /* Messages that are accepted (and made into warning).  */
+  extern struct message_criteria warning_criteria;
+
+  /* Accepted (warning) messages, that are turned into errors.  */
+  extern struct message_criteria error_criteria;
+
+#ifdef __cplusplus
+}
+
+inline message_category
+cat (message_category c1,
+     message_category c2,
+     message_category c3 = mc_none,
+     message_category c4 = mc_none)
+{
+  return static_cast<message_category> (c1 | c2 | c3 | c4);
+}
+
+#endif
+
+#endif//DWARFLINT_MESSAGES_H
diff --git a/src/dwarflint-misc.h b/src/dwarflint-misc.h
new file mode 100644 (file)
index 0000000..bb6dd6d
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef DWARFLINT_MISC_H
+#define DWARFLINT_MISC_H
+
+#include <string.h>
+
+#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 = (typeof (_a->BUF))                            \
+         xrealloc (_a->BUF,                                    \
+                   sizeof (*_a->BUF) * _a->alloc);             \
+      }                                                                \
+  } while (0)
+
+#define WIPE(OBJ) memset (&OBJ, 0, sizeof (OBJ))
+
+#ifdef __cplusplus
+# define IF_CPLUSPLUS(X) X
+#else
+# define IF_CPLUSPLUS(X) /*X*/
+#endif
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+#include "../lib/system.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif//DWARFLINT_MISC_H
diff --git a/src/dwarflint-where.h b/src/dwarflint-where.h
new file mode 100644 (file)
index 0000000..245387a
--- /dev/null
@@ -0,0 +1,79 @@
+#include <stdint.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+# define IF_CPLUSPLUS(X) X
+extern "C"
+{
+#else
+# define IF_CPLUSPLUS(X) /*X*/
+#endif
+
+#define DEBUGINFO_SECTIONS \
+  SEC (info)              \
+  SEC (abbrev)            \
+  SEC (aranges)                   \
+  SEC (pubnames)          \
+  SEC (pubtypes)          \
+  SEC (str)               \
+  SEC (line)              \
+  SEC (loc)               \
+  SEC (mac)               \
+  SEC (ranges)
+
+  enum section_id
+  {
+    sec_invalid = 0,
+
+    /* Debuginfo sections:  */
+#define SEC(n) sec_##n,
+    DEBUGINFO_SECTIONS
+    count_debuginfo_sections,
+#undef SEC
+
+    /* Non-debuginfo sections:  */
+    sec_rel = count_debuginfo_sections,
+    sec_rela,
+
+    /* Non-sections:  */
+    sec_locexpr,       /* Not a section, but a portion of file that
+                          contains a location expression.  */
+    rel_value,         /* For relocations, this denotes that the
+                          relocation is applied to taget value, not a
+                          section offset.  */
+    rel_address,       /* Same as above, but for addresses.  */
+    rel_exec,          /* Some as above, but we expect EXEC bit.  */
+  };
+
+  enum where_formatting
+  {
+    wf_plain = 0, /* Default formatting for given section.  */
+    wf_cudie,
+  };
+
+  struct where
+  {
+    enum section_id section;
+    enum where_formatting formatting;
+    uint64_t addr1; // E.g. a CU offset.
+    uint64_t addr2; // E.g. a DIE address.
+    uint64_t addr3; // E.g. an attribute.
+    struct where *ref; // Related reference, e.g. an abbrev related to given DIE.
+    struct where *next; // For forming "caused-by" chains.
+  };
+
+# define WHERE(SECTION, NEXT)                                          \
+  ((struct where)                                                      \
+   {(SECTION), wf_plain,                                               \
+    (uint64_t)-1, (uint64_t)-1, (uint64_t)-1,                          \
+    NULL, NEXT})
+
+  extern const char *where_fmt (const struct where *wh, char *ptr IF_CPLUSPLUS (= NULL));
+  extern void where_fmt_chain (const struct where *wh, const char *severity);
+  extern void where_reset_1 (struct where *wh, uint64_t addr);
+  extern void where_reset_2 (struct where *wh, uint64_t addr);
+  extern void where_reset_3 (struct where *wh, uint64_t addr);
+
+#ifdef __cplusplus
+}
+#endif
index fd302c2504f6e96b4070e4575ec0e07295863297..7361e826104782d92423f37e5022d8dc285410e0 100644 (file)
@@ -1,7 +1,6 @@
-/* Pedantic checking of DWARF files.
+/* Pedantic checking of DWARF files
    Copyright (C) 2008,2009 Red Hat, Inc.
    This file is part of Red Hat elfutils.
-   Written by Petr Machata <pmachata@redhat.com>, 2008.
 
    Red Hat elfutils is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by the
 # include <config.h>
 #endif
 
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <argp.h>
 #include <assert.h>
 #include <error.h>
-#include <fcntl.h>
 #include <gelf.h>
 #include <inttypes.h>
 #include <libintl.h>
 #include <locale.h>
 #include <stdarg.h>
 #include <stdbool.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <system.h>
 #include "dwarflint-readctx.h"
 #include "dwarf-opcodes.h"
 
-/* Bug report address.  */
-const char *argp_program_bug_address = PACKAGE_BUGREPORT;
-
-#define ARGP_strict    300
-#define ARGP_gnu       301
-#define ARGP_tolerant  302
-#define ARGP_ref        303
-#define ARGP_nohl       304
-#define ARGP_dump_off   305
-
-/* Definitions of arguments for argp functions.  */
-static const struct argp_option options[] =
-{
-  { "strict", ARGP_strict, NULL, 0,
-    N_("Be extremely strict, flag level 2 features."), 0 },
-  { "quiet", 'q', NULL, 0, N_("Do not print anything if successful"), 0 },
-  { "ignore-missing", 'i', NULL, 0,
-    N_("Don't complain if files have no DWARF at all"), 0 },
-  { "gnu", ARGP_gnu, NULL, 0,
-    N_("Binary has been created with GNU toolchain and is therefore known to be \
-broken in certain ways"), 0 },
-  { "tolerant", ARGP_tolerant, NULL, 0,
-    N_("Don't output certain common error messages"), 0 },
-  { "ref", ARGP_ref, NULL, 0,
-    N_("When validating .debug_loc and .debug_ranges, display information about \
-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 },
-  { "dump-offsets", ARGP_dump_off, NULL, 0,
-    N_("Dump DIE offsets to stderr as the tree is iterated."), 0 },
-  { NULL, 0, NULL, 0, NULL, 0 }
-};
-
-/* Short description of program.  */
-static const char doc[] = N_("\
-Pedantic checking of DWARF stored in ELF files.");
-
-/* Strings for arguments in help texts.  */
-static const char args_doc[] = N_("FILE...");
-
-/* Prototype for option handler.  */
-static error_t parse_opt (int key, char *arg, struct argp_state *state);
-
-/* Data structure to communicate with argp functions.  */
-static struct argp argp =
-{
-  options, parse_opt, args_doc, doc, NULL, NULL, NULL
-};
-
-/* If true, we accept silently files without debuginfo.  */
-static bool tolerate_nodebug = false;
-
-static void process_file (Elf *elf, const char *fname, bool only_one);
-
-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
-{
-  struct message_term *terms;
-  size_t size;
-  size_t alloc;
-};
-
-static bool
-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)
-{
-  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 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);
-  for (size_t i = 0; i < cri->size; )
-    {
-      struct message_term *t = cri->terms + i;
-      t->positive |= term->positive;
-      t->negative |= term->negative;
-      if ((t->positive & t->negative) != 0)
-       /* A ^ ~A -> drop the term.  */
-       cri->terms[i] = cri->terms[--cri->size];
-      else
-       ++i;
-    }
-}
-
-static void
-message_cri_or (struct message_criteria *cri, struct message_term *term)
-{
-  assert ((term->positive & term->negative) == 0);
-  REALLOC (cri, terms);
-  cri->terms[cri->size++] = *term;
-}
-
-/* NEG(a&b&~c) -> (~a + ~b + c) */
-static struct message_criteria
-message_cri_neg (struct message_term *term)
-{
-  assert ((term->positive & term->negative) == 0);
-
-  unsigned max = 0;
-#define MC(CAT, ID) max = ID;
-  MESSAGE_CATEGORIES
-#undef MC
-
-  struct message_criteria ret;
-  WIPE (ret);
-  for (size_t i = 0; i < max; ++i)
-    {
-      unsigned mask = 1u << i;
-      if ((term->positive & mask) != 0)
-       message_cri_or (&ret, &(struct message_term){1u << i, mc_none});
-      else if ((term->negative & mask) != 0)
-       message_cri_or (&ret, &(struct message_term){mc_none, 1u << i});
-    }
-
-  return ret;
-}
-
-/* MUL((a&b + c&d), (e&f + g&h)) -> (a&b&e&f + a&b&g&h + c&d&e&f + c&d&g&h) */
-static void
-message_cri_mul (struct message_criteria *cri, struct message_criteria *rhs)
-{
-  struct message_criteria ret;
-  WIPE (ret);
-
-  for (size_t i = 0; i < cri->size; ++i)
-    for (size_t j = 0; j < rhs->size; ++j)
-      {
-       struct message_term t1 = cri->terms[i];
-       struct message_term *t2 = rhs->terms + j;
-       t1.positive |= t2->positive;
-       t1.negative |= t2->negative;
-       if (t1.positive & t1.negative)
-         /* A ^ ~A -> drop the term.  */
-         continue;
-       message_cri_or (&ret, &t1);
-      }
-
-  free (cri->terms);
-  *cri = ret;
-}
-
-/* Reject message if TERM passes.  */
-static void
-message_cri_and_not (struct message_criteria *cri, struct message_term *term)
-{
-  struct message_criteria tmp
-    = message_cri_neg (&(struct message_term) {term->negative, term->positive});
-  message_cri_mul (cri, &tmp);
-  free (tmp.terms);
-}
-
-/* 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 message_accept (&warning_criteria, cat);
-}
-
-static void
-wr_verror (const struct where *wh, const char *format, va_list ap)
-{
-  printf ("error: %s", where_fmt (wh, NULL));
-  vprintf (format, ap);
-  where_fmt_chain (wh, "error");
-  ++error_count;
-}
-
-static void
-wr_vwarning (const struct where *wh, const char *format, va_list ap)
-{
-  printf ("warning: %s", where_fmt (wh, NULL));
-  vprintf (format, ap);
-  where_fmt_chain (wh, "warning");
-  ++error_count;
-}
-
-void
-wr_error (const struct where *wh, const char *format, ...)
-{
-  va_list ap;
-  va_start (ap, format);
-  wr_verror (wh, format, ap);
-  va_end (ap);
-}
-
-void
-wr_warning (const struct where *wh, const char *format, ...)
-{
-  va_list ap;
-  va_start (ap, format);
-  wr_vwarning (wh, format, ap);
-  va_end (ap);
-}
-
-void
-wr_message (enum message_category category, const struct where *wh,
-           const char *format, ...)
-{
-  va_list ap;
-  va_start (ap, format);
-  if (message_accept (&warning_criteria, category))
-    {
-      if (message_accept (&error_criteria, category))
-       wr_verror (wh, format, ap);
-      else
-       wr_vwarning (wh, format, ap);
-    }
-  va_end (ap);
-}
-
-void
-wr_format_padding_message (enum message_category category,
-                          struct where *wh,
-                          uint64_t start, uint64_t end, char *kind)
-{
-  char msg[128];
-  wr_message (category, wh, ": %s: %s.\n",
-             range_fmt (msg, sizeof msg, start, end), kind);
-}
-
-void
-wr_format_leb128_message (struct where *where, const char *what,
-                         const char *purpose,
-                         const unsigned char *begin, const unsigned char *end)
-{
-  enum message_category category = mc_leb128 | mc_acc_bloat | mc_impact_3;
-  char buf[(end - begin) * 3 + 1]; // 2 hexa digits+" " per byte, and term. 0
-  char *ptr = buf;
-  for (; begin < end; ++begin)
-    ptr += sprintf (ptr, " %02x", *begin);
-  wr_message (category, where,
-             ": %s: value %s encoded as `%s'.\n",
-             what, purpose, buf + 1);
-}
-
-void
-wr_message_padding_0 (enum message_category category,
-                     struct where *wh,
-                     uint64_t start, uint64_t end)
-{
-  wr_format_padding_message (category | mc_acc_bloat | mc_impact_1,
-                            wh, start, end,
-                            "unnecessary padding with zero bytes");
-}
-
-void
-wr_message_padding_n0 (enum message_category category,
-                      struct where *wh,
-                      uint64_t start, uint64_t end)
-{
-  wr_format_padding_message (category | mc_acc_bloat | mc_impact_1,
-                            wh, start, end,
-                            "unreferenced non-zero bytes");
-}
-
-/* True if no message is to be printed if the run is succesful.  */
-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 */
-static bool show_refs = false; /* --ref */
-static bool do_high_level = true; /* ! --nohl */
-static bool dump_die_offsets = false; /* --dump-offsets */
-
 /* True if coverage analysis of .debug_ranges vs. ELF sections should
    be done.  */
 static const bool do_range_coverage = false;
 
-static int
-layout_rel_file (Elf *elf)
-{
-  GElf_Ehdr ehdr;
-  if (gelf_getehdr (elf, &ehdr) == NULL)
-    return 1;
-
-  if (ehdr.e_type != ET_REL)
-    return 0;
-
-  /* Taken from libdwfl. */
-  GElf_Addr base = 0;
-  GElf_Addr start = 0, end = 0, bias = 0;
-
-  bool first = true;
-  Elf_Scn *scn = NULL;
-  while ((scn = elf_nextscn (elf, scn)) != NULL)
-    {
-      GElf_Shdr shdr_mem;
-      GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
-      if (unlikely (shdr == NULL))
-       return 1;
-
-      if (shdr->sh_flags & SHF_ALLOC)
-       {
-         const GElf_Xword align = shdr->sh_addralign ?: 1;
-         const GElf_Addr next = (end + align - 1) & -align;
-         if (shdr->sh_addr == 0
-             /* Once we've started doing layout we have to do it all,
-                unless we just layed out the first section at 0 when
-                it already was at 0.  */
-             || (bias == 0 && end > start && end != next))
-           {
-             shdr->sh_addr = next;
-             if (end == base)
-               /* This is the first section assigned a location.
-                  Use its aligned address as the module's base.  */
-               start = base = shdr->sh_addr;
-             else if (unlikely (base & (align - 1)))
-               {
-                 /* If BASE has less than the maximum alignment of
-                    any section, we eat more than the optimal amount
-                    of padding and so make the module's apparent
-                    size come out larger than it would when placed
-                    at zero.  So reset the layout with a better base.  */
-
-                 start = end = base = (base + align - 1) & -align;
-                 Elf_Scn *prev_scn = NULL;
-                 do
-                   {
-                     prev_scn = elf_nextscn (elf, prev_scn);
-                     GElf_Shdr prev_shdr_mem;
-                     GElf_Shdr *prev_shdr = gelf_getshdr (prev_scn,
-                                                          &prev_shdr_mem);
-                     if (unlikely (prev_shdr == NULL))
-                       return 1;
-                     if (prev_shdr->sh_flags & SHF_ALLOC)
-                       {
-                         const GElf_Xword prev_align
-                           = prev_shdr->sh_addralign ?: 1;
-
-                         prev_shdr->sh_addr
-                           = (end + prev_align - 1) & -prev_align;
-                         end = prev_shdr->sh_addr + prev_shdr->sh_size;
-
-                         if (unlikely (! gelf_update_shdr (prev_scn,
-                                                           prev_shdr)))
-                           return 1;
-                       }
-                   }
-                 while (prev_scn != scn);
-                 continue;
-               }
-
-             end = shdr->sh_addr + shdr->sh_size;
-             if (likely (shdr->sh_addr != 0)
-                 && unlikely (! gelf_update_shdr (scn, shdr)))
-               return 1;
-           }
-         else
-           {
-             /* The address is already assigned.  Just track it.  */
-             if (first || end < shdr->sh_addr + shdr->sh_size)
-               end = shdr->sh_addr + shdr->sh_size;
-             if (first || bias > shdr->sh_addr)
-               /* This is the lowest address in the module.  */
-               bias = shdr->sh_addr;
-
-             if ((shdr->sh_addr - bias + base) & (align - 1))
-               /* This section winds up misaligned using BASE.
-                  Adjust BASE upwards to make it congruent to
-                  the lowest section address in the file modulo ALIGN.  */
-               base = (((base + align - 1) & -align)
-                       + (bias & (align - 1)));
-           }
-
-         first = false;
-       }
-    }
-  return 0;
-}
-
-int
-main (int argc, char *argv[])
-{
-  /* Set locale.  */
-  setlocale (LC_ALL, "");
-
-  /* Initialize the message catalog.  */
-  textdomain (PACKAGE_TARNAME);
-
-  /* Parse and process arguments.  */
-  int remaining;
-  argp_parse (&argp, argc, argv, 0, &remaining, NULL);
-
-  /* Initialize warning & error criteria.  */
-  message_cri_or (&warning_criteria,
-                 &(struct message_term){mc_none, mc_none});
-
-  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});
-
-  /* Configure warning & error criteria according to configuration.  */
-  if (tolerate_nodebug)
-    message_cri_and (&warning_criteria,
-                    &(struct message_term){mc_none, mc_elf});
-
-  if (be_gnu)
-    {
-      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_strings});
-      message_cri_and_not (&warning_criteria,
-                          &(struct message_term)
-                           {mc_line | mc_header | mc_acc_bloat, mc_none});
-      message_cri_and (&warning_criteria,
-                      &(struct message_term){mc_none, mc_pubtypes});
-    }
-
-  if (be_tolerant)
-    {
-      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);
-
-  /* Now process all the files given at the command line.  */
-  bool only_one = remaining + 1 == argc;
-  do
-    {
-      /* Open the file.  */
-      int fd = open (argv[remaining], O_RDONLY);
-      if (fd == -1)
-       {
-         error (0, errno, gettext ("cannot open input file"));
-         continue;
-       }
-
-      /* Create an `Elf' descriptor.  */
-      Elf *elf = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL);
-      if (elf == NULL)
-      invalid_elf:
-       wr_error (NULL,
-                 gettext ("Error processing ELF file: %s\n"),
-                 elf_errmsg (-1));
-      else
-       {
-         unsigned int prev_error_count = error_count;
-         if (layout_rel_file (elf))
-           goto invalid_elf;
-
-         process_file (elf, argv[remaining], only_one);
-
-         elf_errno (); /* Clear errno.  */
-         elf_end (elf);
-         int err = elf_errno ();
-         if (err != 0)
-           wr_error (NULL,
-                     gettext ("error while closing Elf descriptor: %s\n"),
-                     elf_errmsg (err));
-
-         if (prev_error_count == error_count && !be_quiet)
-           puts (gettext ("No errors"));
-       }
-
-      close (fd);
-    }
-  while (++remaining < argc);
-
-  return error_count != 0;
-}
-
-/* Handle program arguments.  */
-static error_t
-parse_opt (int key, char *arg __attribute__ ((unused)),
-          struct argp_state *state __attribute__ ((unused)))
+static bool
+check_category (enum message_category cat)
 {
-  switch (key)
-    {
-    case ARGP_strict:
-      be_strict = true;
-      break;
-
-    case ARGP_gnu:
-      be_gnu = true;
-      break;
-
-    case ARGP_tolerant:
-      be_tolerant = true;
-      break;
-
-    case ARGP_ref:
-      show_refs = true;
-      break;
-
-    case ARGP_nohl:
-      do_high_level = false;
-      break;
-
-    case ARGP_dump_off:
-      dump_die_offsets = true;
-      break;
-
-    case 'i':
-      tolerate_nodebug = true;
-      break;
-
-    case 'q':
-      be_quiet = true;
-      be_verbose = false;
-      break;
-
-    case 'v':
-      be_quiet = false;
-      be_verbose = true;
-      break;
-
-    case ARGP_KEY_NO_ARGS:
-      fputs (gettext ("Missing file name.\n"), stderr);
-      argp_help (&argp, stderr, ARGP_HELP_SEE | ARGP_HELP_EXIT_ERR,
-                program_invocation_short_name);
-      exit (1);
-
-    default:
-      return ARGP_ERR_UNKNOWN;
-    }
-  return 0;
+  return message_accept (&warning_criteria, cat);
 }
 
 #define PRI_CU "CU 0x%" PRIx64
@@ -1219,7 +609,7 @@ elf_file_init (struct elf_file *file, Elf *elf)
   return true;
 }
 
-static void
+void
 process_file (Elf *elf, const char *fname, bool only_one)
 {
   if (!only_one)
index b6b44efd90cffb6b2516ed721806a262ef49d464..22dd219046560399da009b358e88cbc5fc8109a9 100644 (file)
 #include "../libdw/libdw.h"
 #include "../libebl/libebl.h"
 #include "dwarflint-coverage.h"
+#include "dwarflint-messages.h"
 
 #ifdef __cplusplus
-# define IF_CPLUSPLUS(X) X
 # include <string>
 extern "C"
 {
 #else
-# define IF_CPLUSPLUS(X) /*X*/
 # include <stdbool.h>
 #endif
 
@@ -50,148 +49,18 @@ extern "C"
   extern bool check_matching_ranges (struct hl_ctx *hlctx);
   extern bool check_expected_trees (struct hl_ctx *hlctx);
   extern bool check_range_out_of_scope (struct hl_ctx *hlctx);
-
-
-  /* Functions and data structures describing location in Dwarf.  */
-
-#define DEBUGINFO_SECTIONS \
-  SEC (info)              \
-  SEC (abbrev)            \
-  SEC (aranges)                   \
-  SEC (pubnames)          \
-  SEC (pubtypes)          \
-  SEC (str)               \
-  SEC (line)              \
-  SEC (loc)               \
-  SEC (mac)               \
-  SEC (ranges)
-
-  enum section_id
-  {
-    sec_invalid = 0,
-
-    /* Debuginfo sections:  */
-#define SEC(n) sec_##n,
-    DEBUGINFO_SECTIONS
-    count_debuginfo_sections,
-#undef SEC
-
-    /* Non-debuginfo sections:  */
-    sec_rel = count_debuginfo_sections,
-    sec_rela,
-
-    /* Non-sections:  */
-    sec_locexpr,       /* Not a section, but a portion of file that
-                          contains a location expression.  */
-    rel_value,         /* For relocations, this denotes that the
-                          relocation is applied to taget value, not a
-                          section offset.  */
-    rel_address,       /* Same as above, but for addresses.  */
-    rel_exec,          /* Some as above, but we expect EXEC bit.  */
-  };
-
-  enum where_formatting
-  {
-    wf_plain = 0, /* Default formatting for given section.  */
-    wf_cudie,
-  };
-
-  struct where
-  {
-    enum section_id section;
-    enum where_formatting formatting;
-    uint64_t addr1; // E.g. a CU offset.
-    uint64_t addr2; // E.g. a DIE address.
-    uint64_t addr3; // E.g. an attribute.
-    struct where *ref; // Related reference, e.g. an abbrev related to given DIE.
-    struct where *next; // For forming "caused-by" chains.
-  };
-
-# define WHERE(SECTION, NEXT)                                          \
-  ((struct where)                                                      \
-   {(SECTION), wf_plain,                                               \
-    (uint64_t)-1, (uint64_t)-1, (uint64_t)-1,                          \
-    NULL, NEXT})
-
-  extern const char *where_fmt (const struct where *wh, char *ptr IF_CPLUSPLUS (= NULL));
-  extern void where_fmt_chain (const struct where *wh, const char *severity);
-  extern void where_reset_1 (struct where *wh, uint64_t addr);
-  extern void where_reset_2 (struct where *wh, uint64_t addr);
-  extern void where_reset_3 (struct where *wh, uint64_t addr);
-
-
-  /* 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,
-
-#define MC(CAT, ID)\
-    mc_##CAT = 1u << ID,
-    MESSAGE_CATEGORIES
-#undef MC
-  };
-
-  extern void wr_error (const struct where *wh, const char *format, ...)
-    __attribute__ ((format (printf, 2, 3)));
-
-  extern void wr_warning (const struct where *wh, const char *format, ...)
-    __attribute__ ((format (printf, 2, 3)));
-
-  extern void wr_message (enum message_category category, const struct where *wh,
-                         const char *format, ...)
-    __attribute__ ((format (printf, 3, 4)));
-
-  extern void wr_format_padding_message (enum message_category category,
-                                        struct where *wh,
-                                        uint64_t start, uint64_t end,
-                                        char *kind);
-
-  extern void wr_format_leb128_message (struct where *where, const char *what,
-                                       const char *purpose,
-                                       const unsigned char *begin,
-                                       const unsigned char *end);
-
-  extern void wr_message_padding_0 (enum message_category category,
-                                   struct where *wh,
-                                   uint64_t start, uint64_t end);
-
-  extern void wr_message_padding_n0 (enum message_category category,
-                                    struct where *wh,
-                                    uint64_t start, uint64_t end);
+  extern void process_file (Elf *elf, const char *fname, bool only_one);
+
+  /* Whole-program options.  */
+  extern bool tolerate_nodebug;
+  extern bool be_quiet; /* -q */
+  extern bool be_verbose; /* -v */
+  extern bool be_strict; /* --strict */
+  extern bool be_gnu; /* --gnu */
+  extern bool be_tolerant; /* --tolerant */
+  extern bool show_refs; /* --ref */
+  extern bool do_high_level; /* ! --nohl */
+  extern bool dump_die_offsets; /* --dump-offsets */
 
   struct relocation
   {