]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
dwarflint: Extract cu_coverage to separate check pass
authorPetr Machata <pmachata@redhat.com>
Mon, 6 Sep 2010 15:44:16 +0000 (17:44 +0200)
committerPetr Machata <pmachata@redhat.com>
Mon, 6 Sep 2010 15:44:16 +0000 (17:44 +0200)
- if the data is incomplete or unavailable, the pass fails just like any
  other pass

13 files changed:
dwarflint/Makefile.am
dwarflint/check_debug_aranges.cc
dwarflint/check_debug_aranges.hh
dwarflint/check_debug_info.cc
dwarflint/check_debug_info.hh
dwarflint/check_debug_loc_range.cc
dwarflint/check_debug_loc_range.hh
dwarflint/check_debug_loc_range.ii [new file with mode: 0644]
dwarflint/cu_coverage.cc [new file with mode: 0644]
dwarflint/cu_coverage.hh [new file with mode: 0644]
dwarflint/cu_coverage.ii [new file with mode: 0644]
dwarflint/dwarflint.hh
dwarflint/low.h

index a79b8cfb382b1881b35cd6156841de16f4847a0b..90ce5b0509e77af316f58d04f777329e1409ba32 100644 (file)
@@ -57,11 +57,12 @@ dwarflint_SOURCES = \
        checks.cc checks.hh checks.ii \
        sections.cc sections.hh sections.ii \
        highlevel_check.cc highlevel_check.hh \
+       cu_coverage.cc cu_coverage.hh cu_coverage.ii \
        check_debug_abbrev.cc check_debug_abbrev.hh check_debug_abbrev.ii \
        check_debug_info.cc check_debug_info.hh check_debug_info.ii \
        check_debug_line.cc \
        check_debug_pub.cc \
-       check_debug_loc_range.cc check_debug_loc_range.hh \
+       check_debug_loc_range.cc check_debug_loc_range.hh check_debug_loc_range.ii \
        check_debug_aranges.cc check_debug_aranges.hh \
        check_matching_ranges.cc \
        check_range_out_of_scope.cc \
index 440d5465a4eb53381bb9bb8f9e8f515235581f3e..4d87b4022a1732cde9ee07af575bbaa0d319230c 100644 (file)
@@ -32,6 +32,7 @@
 #include "check_debug_aranges.hh"
 #include "check_debug_info.hh"
 #include "check_debug_loc_range.hh"
+#include "cu_coverage.hh"
 
 static reg<check_debug_aranges> reg_debug_aranges;
 
@@ -42,6 +43,8 @@ check_debug_aranges::descriptor ()
     (checkdescriptor::create ("check_debug_aranges")
      .groups ("@low")
      .prereq<typeof (*_m_sec_aranges)> ()
+     .prereq<typeof (*_m_info)> ()
+     .prereq<typeof (*_m_cu_coverage)> ()
      .description (
 "Checks for low-level structure of .debug_aranges.  In addition it\n"
 "checks:\n"
@@ -57,24 +60,15 @@ check_debug_aranges::descriptor ()
 
 check_debug_aranges::check_debug_aranges (checkstack &stack, dwarflint &lint)
   : _m_sec_aranges (lint.check (stack, _m_sec_aranges))
+  , _m_info (lint.toplev_check (stack, _m_info))
+  , _m_cu_coverage (lint.toplev_check (stack, _m_cu_coverage))
 {
-  check_debug_info *info = lint.toplev_check<check_debug_info> (stack);
-  coverage *cov = NULL;
-  if (info != NULL)
-    {
-      // xxx If need_ranges is true, we have to load ranges first.
-      // That's a flaw in design of checks, that data should have been
-      // stored in check_ranges, and that should have been requested
-      // explicitly.  But for the time being...
-      if (info->cu_cov.need_ranges)
-       lint.toplev_check<check_debug_ranges> (stack);
-      if (!info->cu_cov.need_ranges)
-       cov = &info->cu_cov.cov;
-    }
+  coverage *cov = _m_cu_coverage != NULL ? &_m_cu_coverage->cov : NULL;
 
   if (!check_aranges_structural (&_m_sec_aranges->file,
                                 &_m_sec_aranges->sect,
-                                info != NULL ? &info->cus.front () : NULL,
+                                _m_info != NULL
+                                  ? &_m_info->cus.front () : NULL,
                                 cov))
     throw check_base::failed ();
 }
index d4427b495e98439f99198bbbbe8e4f7c781fa31d..993a221ada9956fd46b5cbf49251334e99528b99 100644 (file)
 #include "low.h"
 #include "checks.hh"
 #include "sections.ii"
+#include "check_debug_info.ii"
+#include "cu_coverage.ii"
 
 class check_debug_aranges
   : public check<check_debug_aranges>
 {
   section<sec_aranges> *_m_sec_aranges;
+  check_debug_info *_m_info;
+  cu_coverage *_m_cu_coverage;
 
 public:
   static checkdescriptor descriptor ();
index 2d510d718770cb8189deb78d1b9e064c7dfd5293..25ff933515525acce6c6bdf316205411e157b7a4 100644 (file)
@@ -380,7 +380,8 @@ namespace
     struct ref_record *local_die_refs;
     Elf_Data *strings;
     struct coverage *strings_coverage;
-    struct cu_coverage *cu_coverage;
+    struct coverage *pc_coverage;
+    bool *need_rangesp;
   };
 
   typedef void (*value_check_cb_t) (uint64_t addr,
@@ -451,7 +452,7 @@ namespace
       wr_message (*ctx->where, cat (mc_ranges, mc_impact_2))
        << "rangeptr value " << pri::hex (value)
        << " not aligned to CU address size." << std::endl;
-    ctx->cu_coverage->need_ranges = true;
+    *ctx->need_rangesp = true;
     ref_record_add (&ctx->cu->range_refs, value, ctx->where);
   }
 
@@ -496,7 +497,8 @@ namespace
                  struct ref_record *local_die_refs,
                  struct coverage *strings_coverage,
                  struct relocation_data *reloc,
-                 struct cu_coverage *cu_coverage)
+                 struct coverage *pc_coverage,
+                 bool *need_rangesp)
   {
     bool got_die = false;
     uint64_t sibling_addr = 0;
@@ -509,7 +511,8 @@ namespace
       ctx, &where, cu,
       local_die_refs,
       strings, strings_coverage,
-      cu_coverage
+      pc_coverage,
+      need_rangesp
     };
 
     while (!read_ctx_eof (ctx))
@@ -986,7 +989,7 @@ namespace
                  cu->low_pc = value;
 
                if (low_pc != (uint64_t)-1 && high_pc != (uint64_t)-1)
-                 coverage_add (&cu_coverage->cov, low_pc, high_pc - low_pc);
+                 coverage_add (pc_coverage, low_pc, high_pc - low_pc);
              }
          }
        where.ref = NULL;
@@ -1011,7 +1014,7 @@ namespace
            int st = read_die_chain (ver, file, ctx, cu, abbrevs, strings,
                                     local_die_refs,
                                     strings_coverage, reloc,
-                                    cu_coverage);
+                                    pc_coverage, need_rangesp);
            if (st == -1)
              return -1;
            else if (st == 0)
@@ -1074,7 +1077,7 @@ check_debug_info::check_cu_structural (struct read_ctx *ctx,
   if (read_die_chain (ver, _m_file, ctx, cu, &abbrevs, strings,
                      &local_die_refs, strings_coverage,
                      (reloc != NULL && reloc->size > 0) ? reloc : NULL,
-                     &cu_cov) < 0)
+                     &_m_cov, &_m_need_ranges) < 0)
     {
       _m_abbr_skip.push_back (abbrevs.offset);
       retval = false;
@@ -1226,7 +1229,7 @@ check_debug_info::check_debug_info (checkstack &stack, dwarflint &lint)
   , _m_abbrevs (lint.check (stack, _m_abbrevs))
   , _m_cu_headers (lint.check (stack, _m_cu_headers))
 {
-  memset (&cu_cov, 0, sizeof (cu_cov));
+  memset (&_m_cov, 0, sizeof (_m_cov));
   check_info_structural ();
 
   // re-link CUs so that they form a chain again.  This is to
@@ -1257,7 +1260,7 @@ check_debug_info::~check_debug_info ()
       ref_record_free (&it->loc_refs);
       ref_record_free (&it->decl_file_refs);
     }
-  coverage_free (&cu_cov.cov);
+  coverage_free (&_m_cov);
 }
 
 cu *
index 7b33499e9bcc0938ab5e63feb28f079e93571d69..2e2e8fef73b1b1ad294a53a856fdbc337fb0615a 100644 (file)
@@ -44,6 +44,7 @@ public:
   read_cu_headers (checkstack &stack, dwarflint &lint);
 };
 
+/** The pass for in-depth structural analysis of .debug_info.  */
 class check_debug_info
   : public check<check_debug_info>
 {
@@ -58,6 +59,15 @@ class check_debug_info
   // validation.  Check for unused abbrevs should be skipped.
   std::vector< ::Dwarf_Off> _m_abbr_skip;
 
+  // The check pass adds all low_pc/high_pc ranges loaded from DIE
+  // tree into this coverage structure.
+  coverage _m_cov;
+
+  // If, during the check, we find any rangeptr-class attributes, we
+  // set need_ranges to true.  cu_ranges pass then uses this as a hint
+  // whether to request .debug_ranges or not.
+  bool _m_need_ranges;
+
   bool check_cu_structural (struct read_ctx *ctx,
                            struct cu *const cu,
                            Elf_Data *strings,
@@ -69,10 +79,10 @@ class check_debug_info
 public:
   static checkdescriptor descriptor ();
 
-  // The check pass adds all low_pc/high_pc ranges loaded from DIE
-  // tree into this following cu_cov structure.  If it finds any
-  // rangeptr-class attributes, it sets cu_cov.need_ranges to true.
-  cu_coverage cu_cov;
+  coverage const &cov () const { return _m_cov; }
+  bool need_ranges () const { return _m_need_ranges; }
+
+  // This is where the loaded CUs are stored.
   std::vector<cu> cus;
 
   check_debug_info (checkstack &stack, dwarflint &lint);
index b9310db0e91716a0b0fe86308bb522e39f6b0256..e1b397183945eac2111adb7f488a708de6cfd3e8 100644 (file)
@@ -54,7 +54,7 @@ check_debug_ranges::descriptor ()
     (checkdescriptor::create ("check_debug_ranges")
      .groups ("@low")
      .prereq<typeof (*_m_sec_ranges)> ()
-     .prereq<typeof (*_m_cus)> ()
+     .prereq<typeof (*_m_info)> ()
      .description (
 "Checks for low-level structure of .debug_ranges.  In addition it\n"
 "checks:\n"
@@ -79,7 +79,7 @@ check_debug_loc::descriptor ()
     (checkdescriptor::create ("check_debug_loc")
      .groups ("@low")
      .prereq<typeof (*_m_sec_loc)> ()
-     .prereq<typeof (*_m_cus)> ()
+     .prereq<typeof (*_m_info)> ()
      .description (
 "Checks for low-level structure of .debug_loc.  In addition it\n"
 "makes the same checks as .debug_ranges.  For location expressions\n"
@@ -388,7 +388,7 @@ namespace
                          struct sec *sec,
                          struct coverage *coverage,
                          struct coverage_map *coverage_map,
-                         struct cu_coverage *cu_coverage,
+                         struct coverage *pc_coverage,
                          uint64_t addr,
                          struct where const *wh,
                          enum message_category cat)
@@ -523,14 +523,14 @@ namespace
            /* Skip coverage analysis if we have errors or have no base
               (or just don't do coverage analysis at all).  */
            else if (base < (uint64_t)-2 && retval
-                    && (coverage_map != NULL || cu_coverage != NULL))
+                    && (coverage_map != NULL || pc_coverage != NULL))
              {
                uint64_t address = begin_addr + base;
                uint64_t length = end_addr - begin_addr;
                if (coverage_map != NULL)
                  coverage_map_add (coverage_map, address, length, &where, cat);
-               if (cu_coverage != NULL)
-                 coverage_add (&cu_coverage->cov, address, length);
+               if (pc_coverage != NULL)
+                 coverage_add (pc_coverage, address, length);
              }
 
            if (contains_locations)
@@ -601,7 +601,7 @@ namespace
   check_loc_or_range_structural (struct elf_file *file,
                                 struct sec *sec,
                                 struct cu *cu_chain,
-                                struct cu_coverage *cu_coverage)
+                                struct coverage *pc_coverage)
   {
     assert (sec->id == sec_loc || sec->id == sec_ranges);
     assert (cu_chain != NULL);
@@ -666,8 +666,7 @@ namespace
           ranges get recorded, not only those belonging to CUs.
           Perhaps that's undesirable.  */
        if (!check_loc_or_range_ref (file, &ctx, it->cu, sec,
-                                    &coverage, coverage_map,
-                                    sec->id == sec_ranges ? cu_coverage : NULL,
+                                    &coverage, coverage_map, pc_coverage,
                                     off, &it->ref.who, cat))
          retval = false;
        last_off = off;
@@ -699,33 +698,34 @@ namespace
     coverage_free (&coverage);
     coverage_map_free_XA (coverage_map);
 
-    if (retval && cu_coverage != NULL)
-      /* Only drop the flag if we were successful, so that the coverage
-        analysis isn't later done against incomplete data.  */
-      cu_coverage->need_ranges = false;
-
     return retval;
   }
 }
 
 check_debug_ranges::check_debug_ranges (checkstack &stack, dwarflint &lint)
   : _m_sec_ranges (lint.check (stack, _m_sec_ranges))
-  , _m_cus (lint.check (stack, _m_cus))
+  , _m_info (lint.check (stack, _m_info))
 {
+  memset (&_m_cov, 0, sizeof (_m_cov));
   if (!::check_loc_or_range_structural (&_m_sec_ranges->file,
                                        &_m_sec_ranges->sect,
-                                       &_m_cus->cus.front (),
-                                       &_m_cus->cu_cov))
+                                       &_m_info->cus.front (),
+                                       &_m_cov))
     throw check_base::failed ();
 }
 
+check_debug_ranges::~check_debug_ranges ()
+{
+  coverage_free (&_m_cov);
+}
+
 check_debug_loc::check_debug_loc (checkstack &stack, dwarflint &lint)
   : _m_sec_loc (lint.check (stack, _m_sec_loc))
-  , _m_cus (lint.check (stack, _m_cus))
+  , _m_info (lint.check (stack, _m_info))
 {
   if (!::check_loc_or_range_structural (&_m_sec_loc->file,
                                        &_m_sec_loc->sect,
-                                       &_m_cus->cus.front (),
+                                       &_m_info->cus.front (),
                                        NULL))
     throw check_base::failed ();
 }
index d48aebfca00dd142dd90fc40600d1e9c066c1164..c3737e1ce56869c4a3f0a0def09d6adcaa0239ad 100644 (file)
 #include "sections.ii"
 #include "check_debug_info.ii"
 #include "messages.h"
+#include "coverage.hh"
 
 class check_debug_ranges
   : public check<check_debug_ranges>
 {
   section<sec_ranges> *_m_sec_ranges;
-  check_debug_info *_m_cus;
+  check_debug_info *_m_info;
+  coverage _m_cov;
 
 public:
   static checkdescriptor const &descriptor ();
+
+  coverage const &cov () const { return _m_cov; }
   check_debug_ranges (checkstack &stack, dwarflint &lint);
+  ~check_debug_ranges ();
 };
 
 class check_debug_loc
   : public check<check_debug_loc>
 {
   section<sec_loc> *_m_sec_loc;
-  check_debug_info *_m_cus;
+  check_debug_info *_m_info;
 
 public:
   static checkdescriptor const &descriptor ();
diff --git a/dwarflint/check_debug_loc_range.ii b/dwarflint/check_debug_loc_range.ii
new file mode 100644 (file)
index 0000000..a5926e1
--- /dev/null
@@ -0,0 +1,3 @@
+class check_debug_ranges;
+class check_debug_loc;
+struct hole_info;
diff --git a/dwarflint/cu_coverage.cc b/dwarflint/cu_coverage.cc
new file mode 100644 (file)
index 0000000..8fabcda
--- /dev/null
@@ -0,0 +1,53 @@
+/* Pedantic checking of DWARF files
+   Copyright (C) 2010 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>.  */
+
+#include "cu_coverage.hh"
+#include "check_debug_info.hh"
+#include "check_debug_loc_range.hh"
+
+checkdescriptor const &
+cu_coverage::descriptor ()
+{
+  static checkdescriptor cd
+    (checkdescriptor::create ("cu_coverage")
+     .prereq<typeof (*_m_info)> ()
+     .prereq<typeof (*_m_ranges)> ());
+  return cd;
+}
+
+cu_coverage::cu_coverage (checkstack &stack, dwarflint &lint)
+  : _m_info (lint.check (stack, _m_info))
+  , _m_ranges (lint.check_if (_m_info->need_ranges (), stack, _m_ranges))
+{
+  memset (&cov, 0, sizeof (cov));
+  coverage_add_all (&cov, &_m_info->cov ());
+  if (_m_ranges)
+    coverage_add_all (&cov, &_m_ranges->cov ());
+}
+
+cu_coverage::~cu_coverage ()
+{
+  coverage_free (&cov);
+}
diff --git a/dwarflint/cu_coverage.hh b/dwarflint/cu_coverage.hh
new file mode 100644 (file)
index 0000000..00767e9
--- /dev/null
@@ -0,0 +1,50 @@
+/* Pedantic checking of DWARF files
+   Copyright (C) 2010 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>.  */
+
+#ifndef DWARFLINT_CU_COVERAGE_HH
+#define DWARFLINT_CU_COVERAGE_HH
+
+#include "check_debug_info.ii"
+#include "check_debug_loc_range.ii"
+#include "coverage.hh"
+#include "checks.hh"
+
+/** The pass for finalizing cu_coverage.  */
+class cu_coverage
+  : public check<cu_coverage>
+{
+  check_debug_info *_m_info;
+  check_debug_ranges *_m_ranges;
+
+public:
+  static checkdescriptor const &descriptor ();
+
+  coverage cov;
+
+  cu_coverage (checkstack &stack, dwarflint &lint);
+  ~cu_coverage ();
+};
+
+#endif//DWARFLINT_CU_COVERAGE_HH
diff --git a/dwarflint/cu_coverage.ii b/dwarflint/cu_coverage.ii
new file mode 100644 (file)
index 0000000..01d567f
--- /dev/null
@@ -0,0 +1 @@
+class cu_coverage;
index 0e30d2a185460999497dbc6ea1c365f24419b23f..518c33bf00585a6f8b8f538d5fc6a683d41aca06 100644 (file)
@@ -127,6 +127,17 @@ public:
   template <class T>
   T *toplev_check (checkstack &stack,
                   __attribute__ ((unused)) T *fake = NULL);
+
+  template <class T>
+  T *
+  check_if (bool whether, checkstack &stack,
+           __attribute__ ((unused)) T *fake = NULL)
+  {
+    if (whether)
+      return check<T> (stack);
+    else
+      return NULL;
+  }
 };
 
 #endif//DWARFLINT_HH
index 27c3365013361891d64733424e04cf7a5a22e567..13f2a9f767d5460e11bced5ad20bf727140b3c50 100644 (file)
@@ -130,16 +130,6 @@ 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
   struct cu;
   extern bool check_aranges_structural (struct elf_file *file,