]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
dwarflint: Rewrite testing for better extensibility
authorPetr Machata <pmachata@redhat.com>
Thu, 15 Oct 2009 17:21:47 +0000 (19:21 +0200)
committerPetr Machata <pmachata@redhat.com>
Wed, 18 Aug 2010 12:55:11 +0000 (14:55 +0200)
* all tests are actually still done the way they were, but the framework
  is in place

src/dwarflint-checks.hh [new file with mode: 0644]
src/dwarflint-main.cc
src/dwarflint-main.hh [new file with mode: 0644]
src/dwarflint-readctx.h
src/dwarflint.c
src/dwarflint.h

diff --git a/src/dwarflint-checks.hh b/src/dwarflint-checks.hh
new file mode 100644 (file)
index 0000000..37f569b
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef DWARFLINT_CHECKS_HH
+#define DWARFLINT_CHECKS_HH
+
+#include <iostream>
+#include <stdexcept>
+#include <string>
+#include "dwarflint-where.h"
+#include "dwarflint-main.hh"
+
+struct check_base
+{
+  struct failed
+    : public std::runtime_error
+  {
+    failed (std::string const &msg)
+      : std::runtime_error (msg)
+    {
+    }
+  };
+};
+
+template<class T>
+class check
+  : public check_base
+{
+public:
+  static void const *key ()
+  {
+    return reinterpret_cast <void const *> (&key);
+  }
+};
+
+template <class T>
+struct reg
+  : public dwarflint::check_registrar::item
+{
+  reg ()
+  {
+    dwarflint::check_registrar::inst ()->add (this);
+  }
+
+  virtual void run (dwarflint &lint) {
+    lint.toplev_check <T> ();
+  }
+};
+
+template <class T>
+void
+toplev_check (dwarflint &lint)
+{
+  try
+    {
+      lint.check<T> ();
+    }
+  catch (check_base::failed const &f)
+    {
+      std::cout << f.what () << std::endl;
+    }
+}
+
+#endif//DWARFLINT_CHECKS_HH
index 4cf4a202e4573644bcd0a1f94b640e139352cf1b..2b18c4ccf53aecb3ba8e503b1f8c9faa88464c0b 100644 (file)
@@ -37,6 +37,8 @@
 
 #include "dwarflint.h"
 #include "dwarflint-config.h"
+#include "dwarflint-main.hh"
+#include "dwarflint-readctx.h"
 
 /* Bug report address.  */
 const char *argp_program_bug_address = PACKAGE_BUGREPORT;
@@ -254,6 +256,129 @@ layout_rel_file (Elf *elf)
   return 0;
 }
 
+dwarflint::dwarflint (Elf *elf)
+{
+  check_registrar::inst ()->enroll (*this);
+
+  struct elf_file file;
+  if (!elf_file_init (&file, elf))
+    return;
+
+  struct abbrev_table *abbrev_chain = NULL;
+  struct cu *cu_chain = NULL;
+  struct read_ctx ctx;
+
+  /* Don't attempt to do high-level checks if we couldn't initialize
+     high-level context.  The wrapper takes care of printing out error
+     messages if any.  */
+  struct hl_ctx *hlctx = do_high_level ? hl_ctx_new (elf) : NULL;
+
+#define SEC(sec) (file.debugsec[sec_##sec])
+#define HAS_SEC(sec) (SEC(sec) != NULL && SEC(sec)->data != NULL)
+
+  if (likely (HAS_SEC(abbrev)))
+    {
+      read_ctx_init (&ctx, &file, SEC(abbrev)->data);
+      abbrev_chain = abbrev_table_load (&ctx);
+    }
+  else if (!tolerate_nodebug)
+    /* Hard error, not a message.  We can't debug without this.  */
+    wr_error (NULL, ".debug_abbrev data not found.\n");
+
+  Elf_Data *str_data = NULL;
+  if (SEC(str) != NULL)
+    {
+      str_data = SEC(str)->data;
+      if (str_data == NULL)
+       {
+         where wh = WHERE (sec_str, NULL);
+         wr_message (mc_impact_4 | mc_acc_suboptimal | mc_elf, &wh,
+                     ": the section is present but empty.\n");
+       }
+    }
+
+  struct cu_coverage *cu_coverage = NULL;
+  if (abbrev_chain != NULL)
+    {
+      if (likely (HAS_SEC(info)))
+       {
+         cu_coverage
+           = (struct cu_coverage *)calloc (1, sizeof (struct cu_coverage));
+         cu_chain = check_info_structural (&file, SEC(info), abbrev_chain,
+                                           str_data, cu_coverage);
+         if (cu_chain != NULL && hlctx != NULL)
+           check_expected_trees (hlctx);
+       }
+      else if (!tolerate_nodebug)
+       /* Hard error, not a message.  We can't debug without this.  */
+       wr_error (NULL, ".debug_info data not found.\n");
+    }
+
+  bool ranges_sound;
+  if (HAS_SEC(ranges) && cu_chain != NULL)
+    ranges_sound = check_loc_or_range_structural (&file, SEC(ranges),
+                                                 cu_chain, cu_coverage);
+  else
+    ranges_sound = false;
+
+  if (HAS_SEC(loc) && cu_chain != NULL
+      && check_loc_or_range_structural (&file, SEC(loc), cu_chain, NULL)
+      && cu_chain != NULL && hlctx != NULL)
+    check_range_out_of_scope (hlctx);
+
+  if (HAS_SEC(aranges))
+    {
+      read_ctx_init (&ctx, &file, SEC(aranges)->data);
+
+      /* If ranges were needed and not loaded, don't pass them down
+        for CU/aranges coverage analysis. */
+      struct coverage *cov
+       = (cu_coverage != NULL
+          && cu_coverage->need_ranges) ? NULL : &cu_coverage->cov;
+
+      if (check_aranges_structural (&file, SEC(aranges), cu_chain, cov)
+         && ranges_sound && hlctx != NULL && !be_tolerant && !be_gnu)
+       check_matching_ranges (hlctx);
+    }
+
+  if (HAS_SEC(pubnames))
+    check_pub_structural (&file, SEC(pubnames), cu_chain);
+  else if (!tolerate_nodebug)
+    {
+      where wh = WHERE (sec_pubnames, NULL);
+      wr_message (mc_impact_4 | mc_acc_suboptimal | mc_elf,
+                 &wh, ": data not found.\n");
+    }
+
+  if (HAS_SEC(pubtypes))
+    check_pub_structural (&file, SEC(pubtypes), cu_chain);
+  else if (!tolerate_nodebug)
+    {
+      where wh = WHERE (sec_pubtypes, NULL);
+      wr_message (mc_impact_4 | mc_acc_suboptimal | mc_elf | mc_pubtypes,
+                 &wh, ": data not found.\n");
+    }
+
+  if (HAS_SEC(line))
+    check_line_structural (&file, SEC(line), cu_chain);
+  else if (!tolerate_nodebug)
+    {
+      where wh = WHERE (sec_line, NULL);
+      wr_message (mc_impact_4 | mc_acc_suboptimal | mc_elf | mc_loc,
+                 &wh, ": data not found.\n");
+    }
+
+  cu_free (cu_chain);
+  abbrev_table_free (abbrev_chain);
+  if (file.ebl != NULL)
+    ebl_closebackend (file.ebl);
+  free (file.sec);
+  hl_ctx_delete (hlctx);
+
+#undef SEC
+#undef HAS_SEC
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -328,7 +453,9 @@ main (int argc, char *argv[])
          if (layout_rel_file (elf))
            goto invalid_elf;
 
-         process_file (elf, argv[remaining], only_one);
+         if (!only_one)
+           std::cout << std::endl << argv[remaining] << ":" << std::endl;
+         dwarflint lint (elf);
 
          elf_errno (); /* Clear errno.  */
          elf_end (elf);
diff --git a/src/dwarflint-main.hh b/src/dwarflint-main.hh
new file mode 100644 (file)
index 0000000..a6cd8b8
--- /dev/null
@@ -0,0 +1,72 @@
+#ifndef DWARFLINT_HH
+#define DWARFLINT_HH
+
+#include <map>
+#include <vector>
+#include <stdexcept>
+
+class dwarflint
+{
+  typedef std::map <void const *, class check_base *> check_map;
+  check_map _m_checks;
+
+public:
+  struct check_registrar
+  {
+    struct item
+    {
+      virtual void run (dwarflint &lint) = 0;
+    };
+
+    static check_registrar *inst ()
+    {
+      static check_registrar inst;
+      return &inst;
+    }
+
+    void add (item *i)
+    {
+      _m_items.push_back (i);
+    }
+
+  private:
+    friend class dwarflint;
+    void enroll (dwarflint &lint)
+    {
+      for (std::vector <item *>::iterator it = _m_items.begin ();
+          it != _m_items.end (); ++it)
+       (*it)->run (lint);
+    }
+
+    std::vector <item *> _m_items;
+  };
+
+  dwarflint (Elf *elf);
+
+  template <class T>
+  T *
+  check ()
+  {
+    void const *key = T::key ();
+    check_map::iterator it = _m_checks.find (key);
+    T *c;
+    if (it != _m_checks.end ())
+      c = static_cast <T *> (it->second);
+    else
+      {
+       c = new T (*this);
+       if (!_m_checks.insert (std::make_pair (key, c)).second)
+         throw std::runtime_error ("duplicate key");
+      }
+    return c;
+  }
+
+  template <class T>
+  T *
+  check (T *fake)
+  {
+    return check<T> ();
+  }
+};
+
+#endif//DWARFLINT_HH
index 4adcdf56ee8dcee46a3bc7eeaa64607f61b64567..62112eb21bd91ba71f772e5a2a2c0d5b9cae8bc6 100644 (file)
@@ -4,6 +4,11 @@
 #include <stdbool.h>
 #include "../libelf/libelf.h"
 
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
 /* Functions and data structures related to bounds-checked
    reading.  */
 
@@ -44,4 +49,8 @@ const char *read_ctx_read_str (struct read_ctx *ctx);
 bool read_ctx_skip (struct read_ctx *ctx, uint64_t len);
 bool read_ctx_eof (struct read_ctx *ctx);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif
index e83647c6e2e185a09e7e307da21c187d3b2ffaee..0ef8539926563c2b9e425d93ed04e802bff873ce 100644 (file)
@@ -107,12 +107,6 @@ struct abbrev_table
                           abbrevs should be skipped.  */
 };
 
-static struct abbrev_table *abbrev_table_load (struct read_ctx *ctx);
-static void abbrev_table_free (struct abbrev_table *abbr);
-static struct abbrev *abbrev_table_find_abbrev (struct abbrev_table *abbrevs,
-                                               uint64_t abbrev_code);
-
-
 /* Functions and data structures for address record handling.  We use
    that to check that all DIE references actually point to an existing
    die, not somewhere mid-DIE, where it just happens to be
@@ -176,37 +170,8 @@ struct cu
   bool has_pubtypes;            // Likewise for pubtypes.
 };
 
-static void cu_free (struct cu *cu_chain);
 static struct cu *cu_find_cu (struct cu *cu_chain, uint64_t offset);
 
-struct cu_coverage
-{
-  struct coverage cov;
-  bool need_ranges;    /* If all CU DIEs have high_pc/low_pc
-                          attribute pair, we don't need separate
-                          range pass.  Otherwise we do.  As soon as
-                          ranges are projected into cov, the flag
-                          is set to false again.  */
-};
-
-
-/* Functions for checking of structural integrity.  */
-
-static struct cu * check_info_structural (struct elf_file *file,
-                                         struct sec *sec,
-                                         struct abbrev_table *abbrev_chain,
-                                         Elf_Data *strings,
-                                         struct cu_coverage *cu_coverage);
-
-static bool check_aranges_structural (struct elf_file *file,
-                                     struct sec *sec,
-                                     struct cu *cu_chain,
-                                     struct coverage *coverage);
-
-static bool check_pub_structural (struct elf_file *file,
-                                 struct sec *sec,
-                                 struct cu *cu_chain);
-
 static bool check_location_expression (struct elf_file *file,
                                       struct read_ctx *ctx,
                                       struct cu *cu,
@@ -215,20 +180,11 @@ static bool check_location_expression (struct elf_file *file,
                                       size_t length,
                                       struct where *wh);
 
-static bool check_loc_or_range_structural (struct elf_file *file,
-                                          struct sec *sec,
-                                          struct cu *cu_chain,
-                                          struct cu_coverage *cu_coverage);
-
 static bool read_rel (struct elf_file *file,
                      struct sec *sec,
                      Elf_Data *reldata,
                      bool elf_64);
 
-static bool check_line_structural (struct elf_file *file,
-                                  struct sec *sec,
-                                  struct cu *cu_chain);
-
 static bool
 address_aligned (uint64_t addr, uint64_t align)
 {
@@ -241,7 +197,7 @@ necessary_alignment (uint64_t start, uint64_t length, uint64_t align)
   return address_aligned (start + length, align) && length < align;
 }
 
-static bool
+bool
 elf_file_init (struct elf_file *file, Elf *elf)
 {
   WIPE (*file);
@@ -437,118 +393,6 @@ elf_file_init (struct elf_file *file, Elf *elf)
   return true;
 }
 
-void
-process_file (Elf *elf, const char *fname, bool only_one)
-{
-  if (!only_one)
-    printf ("\n%s:\n", fname);
-
-  struct elf_file file;
-  if (!elf_file_init (&file, elf))
-    return;
-
-  struct abbrev_table *abbrev_chain = NULL;
-  struct cu *cu_chain = NULL;
-  struct read_ctx ctx;
-  /* Don't attempt to do high-level checks if we couldn't initialize
-     high-level context.  The wrapper takes care of printing out error
-     messages if any.  */
-  struct hl_ctx *hlctx = do_high_level ? hl_ctx_new (elf) : NULL;
-
-#define SEC(sec) (file.debugsec[sec_##sec])
-#define HAS_SEC(sec) (SEC(sec) != NULL && SEC(sec)->data != NULL)
-
-  if (likely (HAS_SEC(abbrev)))
-    {
-      read_ctx_init (&ctx, &file, SEC(abbrev)->data);
-      abbrev_chain = abbrev_table_load (&ctx);
-    }
-  else if (!tolerate_nodebug)
-    /* Hard error, not a message.  We can't debug without this.  */
-    wr_error (NULL, ".debug_abbrev data not found.\n");
-
-  Elf_Data *str_data = NULL;
-  if (SEC(str) != NULL)
-    {
-      str_data = SEC(str)->data;
-      if (str_data == NULL)
-       wr_message (mc_impact_4 | mc_acc_suboptimal | mc_elf,
-                   &WHERE (sec_str, NULL),
-                   ": the section is present but empty.\n");
-    }
-
-  struct cu_coverage *cu_coverage = NULL;
-  if (abbrev_chain != NULL)
-    {
-      if (likely (HAS_SEC(info)))
-       {
-         cu_coverage = calloc (1, sizeof (struct cu_coverage));
-         cu_chain = check_info_structural (&file, SEC(info), abbrev_chain,
-                                           str_data, cu_coverage);
-         if (cu_chain != NULL && hlctx != NULL)
-           check_expected_trees (hlctx);
-       }
-      else if (!tolerate_nodebug)
-       /* Hard error, not a message.  We can't debug without this.  */
-       wr_error (NULL, ".debug_info data not found.\n");
-    }
-
-  bool ranges_sound;
-  if (HAS_SEC(ranges) && cu_chain != NULL)
-    ranges_sound = check_loc_or_range_structural (&file, SEC(ranges),
-                                                 cu_chain, cu_coverage);
-  else
-    ranges_sound = false;
-
-  if (HAS_SEC(loc) && cu_chain != NULL
-      && check_loc_or_range_structural (&file, SEC(loc), cu_chain, NULL)
-      && cu_chain != NULL && hlctx != NULL)
-    check_range_out_of_scope (hlctx);
-
-  if (HAS_SEC(aranges))
-    {
-      read_ctx_init (&ctx, &file, SEC(aranges)->data);
-
-      /* If ranges were needed and not loaded, don't pass them down
-        for CU/aranges coverage analysis. */
-      struct coverage *cov
-       = (cu_coverage != NULL
-          && cu_coverage->need_ranges) ? NULL : &cu_coverage->cov;
-
-      if (check_aranges_structural (&file, SEC(aranges), cu_chain, cov)
-         && ranges_sound && hlctx != NULL && !be_tolerant && !be_gnu)
-       check_matching_ranges (hlctx);
-    }
-
-  if (HAS_SEC(pubnames))
-    check_pub_structural (&file, SEC(pubnames), cu_chain);
-  else if (!tolerate_nodebug)
-    wr_message (mc_impact_4 | mc_acc_suboptimal | mc_elf,
-               &WHERE (sec_pubnames, NULL), ": data not found.\n");
-
-  if (HAS_SEC(pubtypes))
-    check_pub_structural (&file, SEC(pubtypes), cu_chain);
-  else if (!tolerate_nodebug)
-    wr_message (mc_impact_4 | mc_acc_suboptimal | mc_elf | mc_pubtypes,
-               &WHERE (sec_pubtypes, NULL), ": data not found.\n");
-
-  if (HAS_SEC(line))
-    check_line_structural (&file, SEC(line), cu_chain);
-  else if (!tolerate_nodebug)
-    wr_message (mc_impact_4 | mc_acc_suboptimal | mc_elf | mc_loc,
-               &WHERE (sec_line, NULL), ": data not found.\n");
-
-  cu_free (cu_chain);
-  abbrev_table_free (abbrev_chain);
-  if (file.ebl != NULL)
-    ebl_closebackend (file.ebl);
-  free (file.sec);
-  hl_ctx_delete (hlctx);
-
-#undef SEC
-#undef HAS_SEC
-}
-
 static bool
 checked_read_uleb128 (struct read_ctx *ctx, uint64_t *ret,
                      struct where *where, const char *what)
@@ -702,7 +546,7 @@ is_location_attrib (uint64_t name)
     }
 }
 
-static struct abbrev_table *
+struct abbrev_table *
 abbrev_table_load (struct read_ctx *ctx)
 {
   struct abbrev_table *section_chain = NULL;
@@ -1011,7 +855,7 @@ abbrev_table_load (struct read_ctx *ctx)
   return NULL;
 }
 
-static void
+void
 abbrev_table_free (struct abbrev_table *abbr)
 {
   for (struct abbrev_table *it = abbr; it != NULL; )
@@ -1026,7 +870,7 @@ abbrev_table_free (struct abbrev_table *abbr)
     }
 }
 
-static struct abbrev *
+struct abbrev *
 abbrev_table_find_abbrev (struct abbrev_table *abbrevs, uint64_t abbrev_code)
 {
   size_t a = 0;
@@ -1389,7 +1233,7 @@ coverage_map_free (struct coverage_map *coverage_map)
 }
 
 
-static void
+void
 cu_free (struct cu *cu_chain)
 {
   for (struct cu *it = cu_chain; it != NULL; )
@@ -2635,7 +2479,7 @@ check_cu_structural (struct elf_file *file,
   return retval;
 }
 
-static struct cu *
+struct cu *
 check_info_structural (struct elf_file *file,
                       struct sec *sec,
                       struct abbrev_table *abbrev_chain,
@@ -2898,7 +2742,7 @@ compare_coverage (struct elf_file *file,
 /* COVERAGE is portion of address space covered by CUs (either via
    low_pc/high_pc pairs, or via DW_AT_ranges references).  If
    non-NULL, analysis of arange coverage is done against that set. */
-static bool
+bool
 check_aranges_structural (struct elf_file *file,
                          struct sec *sec,
                          struct cu *cu_chain,
@@ -3142,7 +2986,7 @@ check_aranges_structural (struct elf_file *file,
   return retval;
 }
 
-static bool
+bool
 check_pub_structural (struct elf_file *file,
                      struct sec *sec,
                      struct cu *cu_chain)
@@ -3670,7 +3514,7 @@ check_loc_or_range_ref (struct elf_file *file,
   return retval;
 }
 
-static bool
+bool
 check_loc_or_range_structural (struct elf_file *file,
                               struct sec *sec,
                               struct cu *cu_chain,
@@ -3949,7 +3793,7 @@ read_rel (struct elf_file *file,
   return true;
 }
 
-static bool
+bool
 check_line_structural (struct elf_file *file,
                       struct sec *sec,
                       struct cu *cu_chain)
index bb815951f83b532601808d45508ef95a38ac52fa..cecd6ab5d5b0f8ad2abb12cb406db8f722e2a73a 100644 (file)
@@ -30,6 +30,7 @@
 #include "../libebl/libebl.h"
 #include "dwarflint-coverage.h"
 #include "dwarflint-messages.h"
+#include "dwarflint-readctx.h"
 
 #ifdef __cplusplus
 # include <string>
@@ -39,28 +40,16 @@ extern "C"
 # include <stdbool.h>
 #endif
 
-  /* Entry points for high-level checks.  */
-
   struct hl_ctx;
-
-  /* Check that .debug_aranges and .debug_ranges match.  */
-  extern struct hl_ctx *hl_ctx_new (Elf *elf);
-  extern void hl_ctx_delete (struct hl_ctx *hlctx);
-  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);
-  extern void process_file (Elf *elf, const char *fname, bool only_one);
-
   struct relocation
   {
     uint64_t offset;
     uint64_t addend;
     int symndx;
     int type;
-    bool invalid;              /* Whether this one relocation should be
-                                  ignored.  Necessary so that we don't
-                                  double-report invalid & missing
-                                  relocation.  */
+    bool invalid;      /* Whether this one relocation should be
+                          ignored.  Necessary so that we don't report
+                          invalid & missing relocation twice.  */
   };
 
   struct relocation_data
@@ -105,8 +94,23 @@ extern "C"
     bool addr_64;      /* True if it's 64-bit Elf.  */
     bool other_byte_order; /* True if the file has a byte order
                              different from the host.  */
+    // xxx add CUs etc here?
   };
 
+  /* Check that .debug_aranges and .debug_ranges match.  */
+  extern struct hl_ctx *hl_ctx_new (Elf *elf);
+  extern void hl_ctx_delete (struct hl_ctx *hlctx);
+  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);
+  extern bool elf_file_init (struct elf_file *file, Elf *elf);
+
+  // xxx will go away
+  extern struct abbrev_table * abbrev_table_load (struct read_ctx *ctx);
+  extern void abbrev_table_free (struct abbrev_table *abbr);
+  extern struct abbrev *abbrev_table_find_abbrev (struct abbrev_table *abbrevs,
+                                                 uint64_t abbrev_code);
+
   struct section_coverage
   {
     struct sec *sec;
@@ -125,6 +129,39 @@ extern "C"
     bool allow_overlap;
   };
 
+  struct cu_coverage
+  {
+    struct coverage cov;
+    bool need_ranges;  /* If all CU DIEs have high_pc/low_pc
+                          attribute pair, we don't need separate
+                          range pass.  Otherwise we do.  As soon as
+                          ranges are projected into cov, the flag
+                          is set to false again.  */
+  };
+
+  // xxx low-level check entry points, will go away
+  extern struct cu * check_info_structural (struct elf_file *file,
+                                           struct sec *sec,
+                                           struct abbrev_table *abbrev_chain,
+                                           Elf_Data *strings,
+                                           struct cu_coverage *cu_coverage);
+  extern bool check_loc_or_range_structural (struct elf_file *file,
+                                            struct sec *sec,
+                                            struct cu *cu_chain,
+                                            struct cu_coverage *cu_coverage);
+  extern bool check_aranges_structural (struct elf_file *file,
+                                       struct sec *sec,
+                                       struct cu *cu_chain,
+                                       struct coverage *coverage);
+  extern bool check_pub_structural (struct elf_file *file,
+                                   struct sec *sec,
+                                   struct cu *cu_chain);
+  extern bool check_line_structural (struct elf_file *file,
+                                    struct sec *sec,
+                                    struct cu *cu_chain);
+  extern void cu_free (struct cu *cu_chain);
+
+
   void section_coverage_init (struct section_coverage *sco,
                              struct sec *sec, bool warn);
   bool coverage_map_init (struct coverage_map *coverage_map,