]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
dwarflint: Move .debug_info code into check_debug_info.cc
authorPetr Machata <pmachata@redhat.com>
Fri, 20 Nov 2009 15:45:59 +0000 (16:45 +0100)
committerPetr Machata <pmachata@redhat.com>
Wed, 18 Aug 2010 12:55:13 +0000 (14:55 +0200)
* also cut out parts of stuct cu to struct cu_head
* also constify a bunch of where pointers that are passed around

12 files changed:
src/Makefile.am
src/dwarflint/check_debug_info.cc [new file with mode: 0644]
src/dwarflint/checks-low.cc
src/dwarflint/checks.hh
src/dwarflint/low.c
src/dwarflint/low.h
src/dwarflint/messages.cc
src/dwarflint/messages.h
src/dwarflint/reloc.cc
src/dwarflint/reloc.h
src/dwarflint/where.c
src/dwarflint/where.h

index 3f498e30e96e7e01aab1193be06653d37b0975cc..b5aedd5963fd68901dca001131fe9d3e4103e9d4 100644 (file)
@@ -97,6 +97,7 @@ dwarflint_SOURCES = dwarfstrings.c \
                    dwarflint/all-dies-it.hh \
                    dwarflint/checks-high.hh \
                    dwarflint/check_debug_abbrev.cc \
+                   dwarflint/check_debug_info.cc \
                    dwarflint/check_debug_line.cc \
                    dwarflint/check_matching_ranges.cc \
                    dwarflint/check_range_out_of_scope.cc \
diff --git a/src/dwarflint/check_debug_info.cc b/src/dwarflint/check_debug_info.cc
new file mode 100644 (file)
index 0000000..41f41f5
--- /dev/null
@@ -0,0 +1,345 @@
+/* Routines related to .debug_info.
+
+   Copyright (C) 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>.  */
+
+// xxx drop as soon as not necessary
+#define __STDC_FORMAT_MACROS
+#define PRI_DIE "DIE 0x%" PRIx64
+#include <inttypes.h>
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <cassert>
+
+#include "messages.h"
+#include "low.h"
+#include "checks-low.hh"
+#include "pri.hh"
+
+namespace
+{
+  bool
+  check_category (enum message_category cat)
+  {
+    return message_accept (&warning_criteria, cat);
+  }
+
+  bool
+  check_global_die_references (struct cu *cu_chain)
+  {
+    bool retval = true;
+    for (struct cu *it = cu_chain; it != NULL; it = it->next)
+      for (size_t i = 0; i < it->die_refs.size; ++i)
+       {
+         struct ref *ref = it->die_refs.refs + i;
+         struct cu *ref_cu = NULL;
+         for (struct cu *jt = cu_chain; jt != NULL; jt = jt->next)
+           if (addr_record_has_addr (&jt->die_addrs, ref->addr))
+             {
+               ref_cu = jt;
+               break;
+             }
+
+         if (ref_cu == NULL)
+           {
+             wr_error (&ref->who,
+                       ": unresolved (non-CU-local) reference to " PRI_DIE ".\n",
+                       ref->addr);
+             retval = false;
+           }
+         else if (ref_cu == it)
+           /* This is technically not a problem, so long as the
+              reference is valid, which it is.  But warn about this
+              anyway, perhaps local reference could be formed on fewer
+              number of bytes.  */
+           wr_message (mc_impact_2 | mc_acc_suboptimal | mc_die_rel,
+                       &ref->who,
+                       ": local reference to " PRI_DIE " formed as global.\n",
+                       ref->addr);
+       }
+
+    return retval;
+  }
+
+  std::vector <cu_head>
+  read_info_headers (struct elf_file *file,
+                    struct sec *sec)
+  {
+    struct read_ctx ctx;
+    read_ctx_init (&ctx, sec->data, file->other_byte_order);
+
+    std::vector <cu_head> ret;
+    while (!read_ctx_eof (&ctx))
+      {
+       const unsigned char *cu_begin = ctx.ptr;
+       struct where where = WHERE (sec_info, NULL);
+       where_reset_1 (&where, read_ctx_get_offset (&ctx));
+
+       cu_head head;
+       head.offset = where.addr1;
+       head.where = where;
+
+       /* Reading CU head is a bit tricky, because we don't know if
+          we have run into (superfluous but allowed) zero padding
+          between CUs.  */
+       if (!read_ctx_need_data (&ctx, 4)
+           && check_zero_padding (&ctx, cat (mc_info, mc_header), &where))
+         break;
+
+       /* CU length.  */
+       uint32_t size32;
+       if (!read_ctx_read_4ubyte (&ctx, &size32))
+         {
+           wr_error (where) << "can't read CU length." << std::endl;
+           throw check_base::failed ();
+         }
+       if (size32 == 0
+           && check_zero_padding (&ctx, cat (mc_info, mc_header), &where))
+         break;
+
+       if (!read_size_extra (&ctx, size32, &head.size,
+                             &head.offset_size, &where))
+         throw check_base::failed ();
+
+       if (!read_ctx_need_data (&ctx, head.size))
+         {
+           wr_error (where)
+             << "section doesn't have enough data to read CU of size "
+             << head.size << '.' << std::endl;
+           throw check_base::failed ();
+         }
+
+       /* version + debug_abbrev_offset + address_size */
+       Dwarf_Off cu_head_size = 2 + head.offset_size + 1;
+       if (head.size < cu_head_size)
+         {
+           wr_error (where)
+             << "claimed length of " << head.size
+             << " doesn't even cover CU head." << std::endl;
+           throw check_base::failed ();
+         }
+
+       const unsigned char *cu_end = ctx.ptr + head.size;
+       head.head_size = ctx.ptr - cu_begin; // Length of the head itself.
+       head.total_size = cu_end - cu_begin; // Length including the length field.
+
+       if (!read_ctx_skip (&ctx, head.size))
+         {
+           wr_error (where) << pri::not_enough ("next CU") << std::endl;
+           throw check_base::failed ();
+         }
+
+       ret.push_back (head);
+      }
+
+    return ret;
+  }
+
+  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)
+  {
+    struct ref_record die_refs;
+    WIPE (die_refs);
+
+    struct cu *cu_chain = NULL;
+    bool success = true;
+
+    struct coverage strings_coverage_mem, *strings_coverage = NULL;
+    if (strings != NULL && check_category (mc_strings))
+      {
+       WIPE (strings_coverage_mem);
+       strings_coverage = &strings_coverage_mem;
+      }
+
+    struct relocation_data *reloc = sec->rel.size > 0 ? &sec->rel : NULL;
+
+    std::vector <cu_head> cu_headers = read_info_headers (file, sec);
+    struct read_ctx ctx;
+    read_ctx_init (&ctx, sec->data, file->other_byte_order);
+    for (std::vector <cu_head>::const_iterator it = cu_headers.begin ();
+        it != cu_headers.end (); ++it)
+      {
+       cu_head const &head = *it;
+       where const &where = head.where;
+       struct cu *cur = (cu *)xcalloc (1, sizeof (*cur));
+       cur->head = &head;
+       cur->low_pc = (uint64_t)-1;
+       cur->next = cu_chain;
+       cu_chain = cur;
+
+       assert (read_ctx_need_data (&ctx, head.total_size));
+
+       // Make CU context begin just before the CU length, so that
+       // DIE offsets are computed correctly.
+       struct read_ctx cu_ctx;
+       const unsigned char *cu_end = ctx.ptr + head.total_size;
+       read_ctx_init_sub (&cu_ctx, &ctx, ctx.ptr, cu_end);
+       cu_ctx.ptr += head.head_size;
+
+       if (!check_cu_structural (file, &cu_ctx, cur, abbrev_chain,
+                                 strings, strings_coverage, reloc,
+                                 cu_coverage))
+         {
+           success = false;
+           break;
+         }
+
+       if (cu_ctx.ptr != cu_ctx.end
+           && !check_zero_padding (&cu_ctx, mc_info, &where))
+         {
+           // Garbage coordinates:
+           uint64_t start
+             = read_ctx_get_offset (&ctx) + read_ctx_get_offset (&cu_ctx);
+           uint64_t end = read_ctx_get_offset (&ctx) + head.total_size;
+           wr_message_padding_n0 (mc_info, &where, start, end);
+         }
+
+       int i = read_ctx_skip (&ctx, head.total_size);
+       assert (i);
+      }
+
+    if (success)
+      {
+       if (ctx.ptr != ctx.end)
+         /* Did we read up everything?  */
+         {
+           where wh = WHERE (sec_info, NULL);
+           wr_message (cat (mc_die_other, mc_impact_4), &wh,
+                       ": CU lengths don't exactly match Elf_Data contents.");
+         }
+       else
+         /* Did we consume all the relocations?  */
+         relocation_skip_rest (&sec->rel, sec->id);
+
+       /* If we managed to read up everything, now do abbrev usage
+          analysis.  */
+       for (struct abbrev_table *abbrevs = abbrev_chain;
+            abbrevs != NULL; abbrevs = abbrevs->next)
+         {
+           if (!abbrevs->used)
+             {
+               struct where wh = WHERE (sec_abbrev, NULL);
+               where_reset_1 (&wh, abbrevs->offset);
+               wr_message (mc_impact_4 | mc_acc_bloat | mc_abbrevs, &wh,
+                           ": abbreviation table is never used.\n");
+             }
+           else if (!abbrevs->skip_check)
+             for (size_t i = 0; i < abbrevs->size; ++i)
+               if (!abbrevs->abbr[i].used)
+                 wr_message (mc_impact_3 | mc_acc_bloat | mc_abbrevs,
+                             &abbrevs->abbr[i].where,
+                             ": abbreviation is never used.\n");
+         }
+      }
+
+
+    /* We used to check that all CUs have the same address size.  Now
+       that we validate address_size of each CU against the ELF header,
+       that's not necessary anymore.  */
+
+    bool references_sound = check_global_die_references (cu_chain);
+    ref_record_free (&die_refs);
+
+    if (strings_coverage != NULL)
+      {
+       if (success)
+         {
+           struct hole_info info = {sec_str, mc_strings, strings->d_buf, 0};
+           coverage_find_holes (strings_coverage, 0, strings->d_size,
+                                found_hole, &info);
+         }
+       coverage_free (strings_coverage);
+      }
+
+    if (!success || !references_sound)
+      {
+       cu_free (cu_chain);
+       cu_chain = NULL;
+      }
+
+    /* Reverse the chain, so that it's organized "naturally".  Has
+       significant impact on performance when handling loc_ref and
+       range_ref fields in loc/range validation.  */
+    struct cu *last = NULL;
+    for (struct cu *it = cu_chain; it != NULL; )
+      {
+       struct cu *next = it->next;
+       it->next = last;
+       last = it;
+       it = next;
+      }
+    cu_chain = last;
+
+    return cu_chain;
+  }
+}
+
+check_debug_info::check_debug_info (dwarflint &lint)
+  : _m_sec_info (lint.check (_m_sec_info))
+  , _m_sec_abbrev (lint.check (_m_sec_abbrev))
+  , _m_sec_str (lint.check (_m_sec_str))
+  , _m_abbrevs (lint.check (_m_abbrevs))
+{
+  memset (&cu_cov, 0, sizeof (cu_cov));
+
+  /* xxx wrap C routine before proper loading is in place.  */
+  cu *chain = check_info_structural
+    (&_m_sec_info->file, &_m_sec_info->sect,
+     &_m_abbrevs->abbrevs.begin ()->second,
+     _m_sec_str->sect.data, &cu_cov);
+
+  if (chain == NULL)
+    throw check_base::failed ();
+
+  for (cu *cu = chain; cu != NULL; cu = cu->next)
+    cus.push_back (*cu);
+
+  // re-link CUs so that they form a chain again.  This is to
+  // interface with C-level code.  The last CU's next is null, so we
+  // don't have to re-link it.
+  cu *last = NULL;
+  for (std::vector<cu>::iterator it = cus.begin ();
+       it != cus.end (); ++it)
+    {
+      cu *cur = &*it;
+      if (last != NULL)
+       last->next = cur;
+      last = cur;
+    }
+
+  if (cus.size () > 0)
+    assert (cus.back ().next == NULL);
+}
+
+check_debug_info::~check_debug_info ()
+{
+  cu_free (&cus.back ());
+}
index 778a0e7877bb16065115044d8ec875be2e37d5c1..9a19b668e05b77a411a6520d88194fd83f415764 100644 (file)
@@ -319,47 +319,6 @@ section_base::section_base (dwarflint &lint, section_id secid)
 {
 }
 
-check_debug_info::check_debug_info (dwarflint &lint)
-  : _m_sec_info (lint.check (_m_sec_info))
-  , _m_sec_abbrev (lint.check (_m_sec_abbrev))
-  , _m_sec_str (lint.check (_m_sec_str))
-  , _m_abbrevs (lint.check (_m_abbrevs))
-{
-  memset (&cu_cov, 0, sizeof (cu_cov));
-
-  /* xxx wrap C routine before proper loading is in place.  */
-  cu *chain = check_info_structural
-    (&_m_sec_info->file, &_m_sec_info->sect,
-     &_m_abbrevs->abbrevs.begin ()->second,
-     _m_sec_str->sect.data, &cu_cov);
-
-  if (chain == NULL)
-    throw check_base::failed ();
-
-  for (cu *cu = chain; cu != NULL; cu = cu->next)
-    cus.push_back (*cu);
-
-  // re-link CUs so that they form a chain again.  This is to
-  // interface with C-level code.  The last CU's next is null, so we
-  // don't have to re-link it.
-  cu *last = NULL;
-  for (std::vector<cu>::iterator it = cus.begin ();
-       it != cus.end (); ++it)
-    {
-      cu *cur = &*it;
-      if (last != NULL)
-       last->next = cur;
-      last = cur;
-    }
-  if (cus.size () > 0)
-    assert (cus.back ().next == NULL);
-}
-
-check_debug_info::~check_debug_info ()
-{
-  cu_free (&cus.back ());
-}
-
 check_debug_ranges::check_debug_ranges (dwarflint &lint)
   : _m_sec_ranges (lint.check (_m_sec_ranges))
   , _m_cus (lint.check (_m_cus))
index 84296b1813f931216ea9a07e47e6bf4f03b10a18..ca35a4df10ce400e8a6fc24e4d5beb0b1b33089b 100644 (file)
@@ -15,7 +15,9 @@ template<class T>
 class check
   : public check_base
 {
-public:
+private:
+  template <class X>
+  friend X *dwarflint::check ();
   static void const *key ()
   {
     return reinterpret_cast <void const *> (&key);
index 2eea902db0ee6e467f7cd8269ef490e9ccd8360b..3e3dbc68814a8ca45165119924b740b20ba0198a 100644 (file)
    be done.  */
 static const bool do_range_coverage = false;
 
-static bool
-check_category (enum message_category cat)
-{
-  return message_accept (&warning_criteria, cat);
-}
-
 #define PRI_CU "CU 0x%" PRIx64
 #define PRI_DIE "DIE 0x%" PRIx64
 
@@ -480,7 +474,7 @@ static struct cu *
 cu_find_cu (struct cu *cu_chain, uint64_t offset)
 {
   for (struct cu *it = cu_chain; it != NULL; it = it->next)
-    if (it->offset == offset)
+    if (it->head->offset == offset)
       return it;
   return NULL;
 }
@@ -504,43 +498,6 @@ check_die_references (struct cu *cu,
   return retval;
 }
 
-static bool
-check_global_die_references (struct cu *cu_chain)
-{
-  bool retval = true;
-  for (struct cu *it = cu_chain; it != NULL; it = it->next)
-    for (size_t i = 0; i < it->die_refs.size; ++i)
-      {
-       struct ref *ref = it->die_refs.refs + i;
-       struct cu *ref_cu = NULL;
-       for (struct cu *jt = cu_chain; jt != NULL; jt = jt->next)
-         if (addr_record_has_addr (&jt->die_addrs, ref->addr))
-           {
-             ref_cu = jt;
-             break;
-           }
-
-       if (ref_cu == NULL)
-         {
-           wr_error (&ref->who,
-                     ": unresolved (non-CU-local) reference to " PRI_DIE ".\n",
-                     ref->addr);
-           retval = false;
-         }
-       else if (ref_cu == it)
-         /* This is technically not a problem, so long as the
-            reference is valid, which it is.  But warn about this
-            anyway, perhaps local reference could be formed on fewer
-            number of bytes.  */
-         wr_message (mc_impact_2 | mc_acc_suboptimal | mc_die_rel,
-                     &ref->who,
-                     ": local reference to " PRI_DIE " formed as global.\n",
-                     ref->addr);
-      }
-
-  return retval;
-}
-
 bool
 read_size_extra (struct read_ctx *ctx, uint32_t size32, uint64_t *sizep,
                 int *offset_sizep, struct where *wh)
@@ -573,7 +530,7 @@ read_size_extra (struct read_ctx *ctx, uint32_t size32, uint64_t *sizep,
 bool
 check_zero_padding (struct read_ctx *ctx,
                    enum message_category category,
-                   struct where *wh)
+                   struct where const *wh)
 {
   assert (ctx->ptr != ctx->end);
   const unsigned char *save_ptr = ctx->ptr;
@@ -772,11 +729,11 @@ read_die_chain (dwarf_version_h ver,
 
   while (!read_ctx_eof (ctx))
     {
-      where = cu->where;
+      where = cu->head->where;
       die_off = read_ctx_get_offset (ctx);
       /* Shift reported DIE offset by CU offset, to match the way
         readelf reports DIEs.  */
-      where_reset_2 (&where, die_off + cu->offset);
+      where_reset_2 (&where, die_off + cu->head->offset);
 
       uint64_t abbr_code;
 
@@ -785,7 +742,7 @@ read_die_chain (dwarf_version_h ver,
 
 #define DEF_PREV_WHERE                                                 \
       struct where prev_where = where;                                 \
-      where_reset_2 (&prev_where, prev_die_off + cu->offset)
+      where_reset_2 (&prev_where, prev_die_off + cu->head->offset)
 
       /* Check sibling value advertised last time through the loop.  */
       if (sibling_addr != 0)
@@ -847,7 +804,7 @@ read_die_chain (dwarf_version_h ver,
        }
       abbrev->used = true;
 
-      addr_record_add (&cu->die_addrs, cu->offset + die_off);
+      addr_record_add (&cu->die_addrs, cu->head->offset + die_off);
 
       uint64_t low_pc = (uint64_t)-1, high_pc = (uint64_t)-1;
       bool low_pc_relocated = false, high_pc_relocated = false;
@@ -913,7 +870,7 @@ read_die_chain (dwarf_version_h ver,
            if (local_die_refs != NULL)
              /* Address holds a CU-local reference, so add CU offset
                 to turn it into section offset.  */
-             ref_record_add (local_die_refs, addr += cu->offset, who);
+             ref_record_add (local_die_refs, addr += cu->head->offset, who);
          }
 
          /* Callback for global DIE references.  */
@@ -972,7 +929,7 @@ read_die_chain (dwarf_version_h ver,
            ref_record_add (&cu->loc_refs, value, who);
          }
 
-         uint64_t ctx_offset = read_ctx_get_offset (ctx) + cu->offset;
+         uint64_t ctx_offset = read_ctx_get_offset (ctx) + cu->head->offset;
          bool type_is_rel = file->ehdr.e_type == ET_REL;
 
          /* Attribute value.  */
@@ -1008,7 +965,7 @@ read_die_chain (dwarf_version_h ver,
              switch (form)
                {
                case DW_FORM_data8:
-                 if (cu->offset_size == 4)
+                 if (cu->head->offset_size == 4)
                    wr_error (&where,
                              ": location attribute with form \"%s\" in 32-bit CU.\n",
                              dwarf_form_string (form));
@@ -1042,7 +999,7 @@ read_die_chain (dwarf_version_h ver,
            switch (form)
              {
              case DW_FORM_data8:
-               if (cu->offset_size == 4)
+               if (cu->head->offset_size == 4)
                  wr_error (&where,
                            ": %s with form DW_FORM_data8 in 32-bit CU.\n",
                            dwarf_attr_string (it->name));
@@ -1093,7 +1050,7 @@ read_die_chain (dwarf_version_h ver,
            case DW_FORM_strp:
              value_check_cb = check_strp;
            case DW_FORM_sec_offset:
-             if (!read_ctx_read_offset (ctx, cu->offset_size == 8, &value))
+             if (!read_ctx_read_offset (ctx, cu->head->offset_size == 8, &value))
                {
                cant_read:
                  wr_error (&where, ": can't read value of attribute %s.\n",
@@ -1102,7 +1059,7 @@ read_die_chain (dwarf_version_h ver,
                }
 
              relocate = rel_require;
-             width = cu->offset_size;
+             width = cu->head->offset_size;
              break;
 
            case DW_FORM_string:
@@ -1112,7 +1069,7 @@ read_die_chain (dwarf_version_h ver,
 
            case DW_FORM_ref_addr:
              value_check_cb = check_die_ref_global;
-             width = cu->offset_size;
+             width = cu->head->offset_size;
 
              if (cu->version == 2)
            case DW_FORM_addr:
@@ -1217,7 +1174,7 @@ read_die_chain (dwarf_version_h ver,
                if (is_location_attrib (it->name))
                  {
                    uint64_t expr_start
-                     = cu->offset + read_ctx_get_offset (ctx);
+                     = cu->head->offset + read_ctx_get_offset (ctx);
                    if (!check_location_expression (file, ctx, cu, expr_start,
                                                    reloc, length, &where))
                      return -1;
@@ -1344,7 +1301,7 @@ static bool
 read_address_size (struct elf_file *file,
                   struct read_ctx *ctx,
                   uint8_t *address_sizep,
-                  struct where *where)
+                  struct where const *where)
 {
   uint8_t address_size;
   if (!read_ctx_read_ubyte (ctx, &address_size))
@@ -1372,7 +1329,7 @@ read_address_size (struct elf_file *file,
   return true;
 }
 
-static bool
+bool
 check_cu_structural (struct elf_file *file,
                     struct read_ctx *ctx,
                     struct cu *const cu,
@@ -1383,48 +1340,48 @@ check_cu_structural (struct elf_file *file,
                     struct cu_coverage *cu_coverage)
 {
   if (dump_die_offsets)
-    fprintf (stderr, "%s: CU starts\n", where_fmt (&cu->where, NULL));
+    fprintf (stderr, "%s: CU starts\n", where_fmt (&cu->head->where, NULL));
   bool retval = true;
 
   /* Version.  */
   uint16_t version;
   if (!read_ctx_read_2ubyte (ctx, &version))
     {
-      wr_error (&cu->where, ": can't read version.\n");
+      wr_error (&cu->head->where, ": can't read version.\n");
       return false;
     }
   dwarf_version_h ver = get_dwarf_version (version);
   if (ver == NULL)
     return false;
-  if (version == 2 && cu->offset_size == 8) // xxx?
+  if (version == 2 && cu->head->offset_size == 8) // xxx?
     /* Keep going.  It's a standard violation, but we may still be
        able to read the unit under consideration and do high-level
        checks.  */
-    wr_error (&cu->where, ": invalid 64-bit unit in DWARF 2 format.\n");
+    wr_error (&cu->head->where, ": invalid 64-bit unit in DWARF 2 format.\n");
   cu->version = version;
 
   /* Abbrev offset.  */
   uint64_t abbrev_offset;
-  uint64_t ctx_offset = read_ctx_get_offset (ctx) + cu->offset;
-  if (!read_ctx_read_offset (ctx, cu->offset_size == 8, &abbrev_offset))
+  uint64_t ctx_offset = read_ctx_get_offset (ctx) + cu->head->offset;
+  if (!read_ctx_read_offset (ctx, cu->head->offset_size == 8, &abbrev_offset))
     {
-      wr_error (&cu->where, ": can't read abbrev offset.\n");
+      wr_error (&cu->head->where, ": can't read abbrev offset.\n");
       return false;
     }
 
   struct relocation *rel
-    = relocation_next (reloc, ctx_offset, &cu->where, skip_mismatched);
+    = relocation_next (reloc, ctx_offset, &cu->head->where, skip_mismatched);
   if (rel != NULL)
-    relocate_one (file, reloc, rel, cu->offset_size,
-                 &abbrev_offset, &cu->where, sec_abbrev, NULL);
+    relocate_one (file, reloc, rel, cu->head->offset_size,
+                 &abbrev_offset, &cu->head->where, sec_abbrev, NULL);
   else if (file->ehdr.e_type == ET_REL)
-    wr_message (mc_impact_2 | mc_info | mc_reloc, &cu->where,
+    wr_message (mc_impact_2 | mc_info | mc_reloc, &cu->head->where,
                PRI_LACK_RELOCATION, "abbrev offset");
 
   /* Address size.  */
   {
     uint8_t address_size;
-    if (!read_address_size (file, ctx, &address_size, &cu->where))
+    if (!read_address_size (file, ctx, &address_size, &cu->head->where))
       return false;
     cu->address_size = address_size;
   }
@@ -1437,7 +1394,7 @@ check_cu_structural (struct elf_file *file,
 
   if (abbrevs == NULL)
     {
-      wr_error (&cu->where,
+      wr_error (&cu->head->where,
                ": couldn't find abbrev section with offset %" PRId64 ".\n",
                abbrev_offset);
       return false;
@@ -1449,7 +1406,7 @@ check_cu_structural (struct elf_file *file,
   struct ref_record local_die_refs;
   WIPE (local_die_refs);
 
-  cu->cudie_offset = read_ctx_get_offset (ctx) + cu->offset;
+  cu->cudie_offset = read_ctx_get_offset (ctx) + cu->head->offset;
   if (read_die_chain (ver, file, ctx, cu, abbrevs, strings,
                      &local_die_refs, strings_coverage,
                      (reloc != NULL && reloc->size > 0) ? reloc : NULL,
@@ -1465,194 +1422,6 @@ check_cu_structural (struct elf_file *file,
   return retval;
 }
 
-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)
-{
-  struct read_ctx ctx;
-  read_ctx_init (&ctx, sec->data, file->other_byte_order);
-
-  struct ref_record die_refs;
-  WIPE (die_refs);
-
-  struct cu *cu_chain = NULL;
-
-  bool success = true;
-
-  struct coverage strings_coverage_mem, *strings_coverage = NULL;
-  if (strings != NULL && check_category (mc_strings))
-    {
-      WIPE (strings_coverage_mem);
-      strings_coverage = &strings_coverage_mem;
-    }
-
-  struct relocation_data *reloc = sec->rel.size > 0 ? &sec->rel : NULL;
-  while (!read_ctx_eof (&ctx))
-    {
-      const unsigned char *cu_begin = ctx.ptr;
-      struct where where = WHERE (sec_info, NULL);
-      where_reset_1 (&where, read_ctx_get_offset (&ctx));
-
-      struct cu *cur = xcalloc (1, sizeof (*cur));
-      cur->offset = where.addr1;
-      cur->next = cu_chain;
-      cur->where = where;
-      cur->low_pc = (uint64_t)-1;
-      cu_chain = cur;
-
-      uint32_t size32;
-      uint64_t size;
-
-      /* Reading CU header is a bit tricky, because we don't know if
-        we have run into (superfluous but allowed) zero padding.  */
-      if (!read_ctx_need_data (&ctx, 4)
-         && check_zero_padding (&ctx, mc_info | mc_header, &where))
-       break;
-
-      /* CU length.  */
-      if (!read_ctx_read_4ubyte (&ctx, &size32))
-       {
-         wr_error (&where, ": can't read CU length.\n");
-         success = false;
-         break;
-       }
-      if (size32 == 0 && check_zero_padding (&ctx, mc_info | mc_header, &where))
-       break;
-
-      if (!read_size_extra (&ctx, size32, &size, &cur->offset_size, &where))
-       {
-         success = false;
-         break;
-       }
-
-      if (!read_ctx_need_data (&ctx, size))
-       {
-         wr_error (&where,
-                   ": section doesn't have enough data"
-                   " to read CU of size %" PRId64 ".\n", size);
-         ctx.ptr = ctx.end;
-         success = false;
-         break;
-       }
-
-      const unsigned char *cu_end = ctx.ptr + size;
-      cur->length = cu_end - cu_begin; // Length including the length field.
-
-      /* version + debug_abbrev_offset + address_size */
-      uint64_t cu_header_size = 2 + cur->offset_size + 1;
-      if (size < cu_header_size)
-       {
-         wr_error (&where, ": claimed length of %" PRIx64
-                   " doesn't even cover CU header.\n", size);
-         success = false;
-         break;
-       }
-      else
-       {
-         /* Make CU context begin just before the CU length, so that DIE
-            offsets are computed correctly.  */
-         struct read_ctx cu_ctx;
-         if (!read_ctx_init_sub (&cu_ctx, &ctx, cu_begin, cu_end))
-           {
-           not_enough:
-             wr_error (&where, PRI_NOT_ENOUGH, "next CU");
-             success = false;
-             break;
-           }
-         cu_ctx.ptr = ctx.ptr;
-
-         if (!check_cu_structural (file, &cu_ctx, cur, abbrev_chain,
-                                   strings, strings_coverage, reloc,
-                                   cu_coverage))
-           {
-             success = false;
-             break;
-           }
-         if (cu_ctx.ptr != cu_ctx.end
-             && !check_zero_padding (&cu_ctx, mc_info, &where))
-           wr_message_padding_n0 (mc_info, &where,
-                                  read_ctx_get_offset (&ctx),
-                                  read_ctx_get_offset (&ctx) + size);
-       }
-
-      if (!read_ctx_skip (&ctx, size))
-       goto not_enough;
-    }
-
-  if (success)
-    {
-      if (ctx.ptr != ctx.end)
-       /* Did we read up everything?  */
-       wr_message (mc_die_other | mc_impact_4,
-                   &WHERE (sec_info, NULL),
-                   ": CU lengths don't exactly match Elf_Data contents.");
-      else
-       /* Did we consume all the relocations?  */
-       relocation_skip_rest (&sec->rel, sec->id);
-
-      /* If we managed to read up everything, now do abbrev usage
-        analysis.  */
-      for (struct abbrev_table *abbrevs = abbrev_chain;
-          abbrevs != NULL; abbrevs = abbrevs->next)
-       {
-         if (!abbrevs->used)
-           {
-             struct where wh = WHERE (sec_abbrev, NULL);
-             where_reset_1 (&wh, abbrevs->offset);
-             wr_message (mc_impact_4 | mc_acc_bloat | mc_abbrevs, &wh,
-                         ": abbreviation table is never used.\n");
-           }
-         else if (!abbrevs->skip_check)
-           for (size_t i = 0; i < abbrevs->size; ++i)
-             if (!abbrevs->abbr[i].used)
-               wr_message (mc_impact_3 | mc_acc_bloat | mc_abbrevs,
-                           &abbrevs->abbr[i].where,
-                           ": abbreviation is never used.\n");
-       }
-    }
-
-
-  /* We used to check that all CUs have the same address size.  Now
-     that we validate address_size of each CU against the ELF header,
-     that's not necessary anymore.  */
-
-  bool references_sound = check_global_die_references (cu_chain);
-  ref_record_free (&die_refs);
-
-  if (strings_coverage != NULL)
-    {
-      if (success)
-       coverage_find_holes (strings_coverage, 0, strings->d_size, found_hole,
-                            &((struct hole_info)
-                              {sec_str, mc_strings, strings->d_buf, 0}));
-      coverage_free (strings_coverage);
-    }
-
-  if (!success || !references_sound)
-    {
-      cu_free (cu_chain);
-      cu_chain = NULL;
-    }
-
-  /* Reverse the chain, so that it's organized "naturally".  Has
-     significant impact on performance when handling loc_ref and
-     range_ref fields in loc/range validation.  */
-  struct cu *last = NULL;
-  for (struct cu *it = cu_chain; it != NULL; )
-    {
-      struct cu *next = it->next;
-      it->next = last;
-      last = it;
-      it = next;
-    }
-  cu_chain = last;
-
-  return cu_chain;
-}
-
 static struct coverage_map *
 coverage_map_alloc_XA (struct elf_file *elf, bool allow_overlap)
 {
@@ -2047,7 +1816,7 @@ check_pub_structural (struct elf_file *file,
        wr_error (&where, ": unresolved reference to " PRI_CU ".\n", cu_offset);
       if (cu != NULL)
        {
-         where.ref = &cu->where;
+         where.ref = &cu->head->where;
          bool *has = sec->id == sec_pubnames
                        ? &cu->has_pubnames : &cu->has_pubtypes;
          if (*has)
@@ -2065,11 +1834,12 @@ check_pub_structural (struct elf_file *file,
          retval = false;
          goto next;
        }
-      if (cu != NULL && cu_len != cu->length)
+      if (cu != NULL && cu_len != cu->head->total_size)
        {
          wr_error (&where,
                    ": the table covers length %" PRId64
-                   " but CU has length %" PRId64 ".\n", cu_len, cu->length);
+                   " but CU has length %" PRId64 ".\n",
+                   cu_len, cu->head->total_size);
          retval = false;
          goto next;
        }
@@ -2091,7 +1861,8 @@ check_pub_structural (struct elf_file *file,
            break;
 
          if (cu != NULL
-             && !addr_record_has_addr (&cu->die_addrs, offset + cu->offset))
+             && !addr_record_has_addr (&cu->die_addrs,
+                                       offset + cu->head->offset))
            {
              wr_error (&where,
                        ": unresolved reference to " PRI_DIE ".\n", offset);
index 35f7a3a9942800ea3787a8d5aa06e56a9aa3bd54..795f34260e7f8769ebd32a7b89d42ea81f3fc58c 100644 (file)
@@ -110,7 +110,7 @@ extern "C"
                                 size_t num_supported, struct where *where, ...);
   extern bool check_zero_padding (struct read_ctx *ctx,
                                  enum message_category category,
-                                 struct where *wh);
+                                 struct where const *wh);
 
   struct section_coverage
   {
@@ -141,11 +141,15 @@ extern "C"
   };
 
   // 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);
+  struct cu;
+  extern bool check_cu_structural (struct elf_file *file,
+                                  struct read_ctx *ctx,
+                                  struct cu *const cu,
+                                  struct abbrev_table *abbrev_chain,
+                                  Elf_Data *strings,
+                                  struct coverage *strings_coverage,
+                                  struct relocation_data *reloc,
+                                  struct cu_coverage *cu_coverage);
   extern bool check_loc_or_range_structural (struct elf_file *file,
                                             struct sec *sec,
                                             struct cu *cu_chain,
@@ -217,22 +221,32 @@ extern "C"
     bool used;
   };
 
-  struct cu
+  struct cu_head
   {
-    struct cu *next;
     uint64_t offset;
+    Dwarf_Off size;               // Size of this CU.
+    Dwarf_Off head_size;          // Size from begin to 1st byte of CU.
+    Dwarf_Off total_size;         // size + head_size
+
+    int offset_size;             // Offset size in this CU.
+    struct where where;           // Where was this section defined.
+    Dwarf_Off abbrev_offset;      // Abbreviation section that this CU uses.
+  };
+
+  struct cu
+  {
+    struct cu *next;              // For compatibility with C level.
+                                  // xxx will probably go away eventually
+    struct cu_head const *head;
     uint64_t cudie_offset;
-    uint64_t length;
     uint64_t low_pc;              // DW_AT_low_pc value of CU DIE, -1 if not present.
     struct addr_record die_addrs; // Addresses where DIEs begin in this CU.
     struct ref_record die_refs;   // DIE references into other CUs from this CU.
     struct ref_record loc_refs;   // references into .debug_loc from this CU.
     struct ref_record range_refs; // references into .debug_ranges from this CU.
-    struct ref_record line_refs;       // references into .debug_line from this CU.
-    struct where where;           // Where was this section defined.
+    struct ref_record line_refs;  // references into .debug_line from this CU.
     int address_size;             // Address size in bytes on the target machine.
-    int offset_size;           // Offset size in this CU.
-    int version;                       // CU version
+    int version;                  // CU version
     bool has_arange;              // Whether we saw arange section pointing to this CU.
     bool has_pubnames;            // Likewise for pubnames.
     bool has_pubtypes;            // Likewise for pubtypes.
index c6d647e80d51d62e3f8a3965a44494ee50d89c09..1dba92e7980f807a37200a0ba23a866818edb57d 100644 (file)
@@ -280,7 +280,7 @@ wr_message (where const &wh, message_category category)
 
 void
 wr_format_padding_message (unsigned long category,
-                          struct where *wh,
+                          struct where const *wh,
                           uint64_t start, uint64_t end, char const *kind)
 {
   char msg[128];
@@ -289,7 +289,8 @@ wr_format_padding_message (unsigned long category,
 }
 
 void
-wr_format_leb128_message (struct where *where, const char *what,
+wr_format_leb128_message (struct where const *where,
+                         const char *what,
                          const char *purpose,
                          const unsigned char *begin, const unsigned char *end)
 {
@@ -305,7 +306,7 @@ wr_format_leb128_message (struct where *where, const char *what,
 
 void
 wr_message_padding_0 (unsigned long category,
-                     struct where *wh,
+                     struct where const *wh,
                      uint64_t start, uint64_t end)
 {
   wr_format_padding_message (category | mc_acc_bloat | mc_impact_1,
@@ -315,7 +316,7 @@ wr_message_padding_0 (unsigned long category,
 
 void
 wr_message_padding_n0 (unsigned long category,
-                      struct where *wh,
+                      struct where const *wh,
                       uint64_t start, uint64_t end)
 {
   wr_format_padding_message (category | mc_acc_bloat | mc_impact_1,
index 5f88722d4948f8fe0d4025cf31541dd50fb20f8b..19af4281a9016652d09ecbb4f6985450d0f0a015 100644 (file)
@@ -103,21 +103,22 @@ extern "C"
     __attribute__ ((format (printf, 3, 4)));
 
   extern void wr_format_padding_message (unsigned long category,
-                                        struct where *wh,
+                                        struct where const *wh,
                                         uint64_t start, uint64_t end,
                                         char const *kind);
 
-  extern void wr_format_leb128_message (struct where *where, const char *what,
+  extern void wr_format_leb128_message (struct where const *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,
+                                   struct where const *wh,
                                    uint64_t start, uint64_t end);
 
   extern void wr_message_padding_n0 (unsigned long category,
-                                    struct where *wh,
+                                    struct where const *wh,
                                     uint64_t start, uint64_t end);
 
   extern bool message_accept (struct message_criteria const *cri,
index 8bab5ac9848e16edfa306bd430af1f44169097e8..c3ea6e2ccbe7287f12dfb7edd70c9e9386d331a2 100644 (file)
@@ -6,7 +6,7 @@
 #include <cassert>
 
 static struct where
-where_from_reloc (struct relocation_data *reloc, struct where *ref)
+where_from_reloc (struct relocation_data *reloc, struct where const *ref)
 {
   struct where where
     = WHERE (reloc->type == SHT_REL ? sec_rel : sec_rela, NULL);
@@ -17,7 +17,7 @@ where_from_reloc (struct relocation_data *reloc, struct where *ref)
 
 relocation *
 relocation_next (relocation_data *reloc, uint64_t offset,
-                struct where *where, enum skip_type st)
+                struct where const *where, enum skip_type st)
 {
   if (reloc == NULL || reloc->rel == NULL)
     return NULL;
@@ -61,7 +61,7 @@ relocation_next (relocation_data *reloc, uint64_t offset,
    matching that offset is immediately yielded.  */
 void
 relocation_skip (struct relocation_data *reloc, uint64_t offset,
-                struct where *where, enum skip_type st)
+                struct where const *where, enum skip_type st)
 {
   if (reloc != NULL && reloc->rel != NULL)
     relocation_next (reloc, offset - 1, where, st);
@@ -88,7 +88,8 @@ void
 relocate_one (struct elf_file *file,
              struct relocation_data *reloc,
              struct relocation *rel,
-             unsigned width, uint64_t *value, struct where *where,
+             unsigned width, uint64_t *value,
+             struct where const *where,
              enum section_id offset_into, GElf_Sym **symptr)
 {
   if (rel->invalid)
index 0804155eb3e172c56f4493fa1eb1fbd5c8ef8d2d..d3a90748a3bc0e5aa5155b2f29db7498f0937c61 100644 (file)
@@ -72,11 +72,12 @@ extern "C"
   };
 
   struct relocation *relocation_next (struct relocation_data *reloc,
-                                     uint64_t offset, struct where *where,
+                                     uint64_t offset,
+                                     struct where const *where,
                                      enum skip_type st);
 
   void relocation_skip (struct relocation_data *reloc, uint64_t offset,
-                       struct where *where, enum skip_type st);
+                       struct where const *where, enum skip_type st);
 
   void relocation_skip_rest (struct relocation_data *reloc,
                             enum section_id id);
@@ -84,7 +85,8 @@ extern "C"
   void relocate_one (struct elf_file *file,
                     struct relocation_data *reloc,
                     struct relocation *rel,
-                    unsigned width, uint64_t *value, struct where *where,
+                    unsigned width, uint64_t *value,
+                    struct where const *where,
                     enum section_id offset_into, GElf_Sym **symptr);
 
 #define PRI_LACK_RELOCATION ": %s seems to lack a relocation.\n"
index 9bbd6de03f133d0b2cfcb1269c5e21986bbaeaac..6e3d5d89c42fed5cb7fe20c9add984b2641f192a 100644 (file)
@@ -115,7 +115,7 @@ where_fmt (const struct where *wh, char *ptr)
       ptr = stpcpy (buf, inf->name);
       if (is_reloc)
        {
-         struct where *ref = wh->ref;
+         struct where const *ref = wh->ref;
          assert (ref != NULL);
          if (ref->section == sec_locexpr)
            {
@@ -155,7 +155,7 @@ void
 where_fmt_chain (const struct where *wh, const char *severity)
 {
   if (wh != NULL && show_refs)
-    for (struct where *it = wh->next; it != NULL; it = it->next)
+    for (struct where const *it = wh->next; it != NULL; it = it->next)
       printf ("%s: %s: caused by this reference.\n",
              severity, where_fmt (it, NULL));
 }
index 0522c72b47e518347f4c3f283114f037e31d2c6a..5155cae7dd5c44d3440f9616036e65de0f9bfc3d 100644 (file)
@@ -62,8 +62,9 @@ extern "C"
     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.
+    struct where const *ref; // Related reference, e.g. an abbrev
+                            // related to given DIE.
+    struct where const *next; // For forming "caused-by" chains.
   };
 
 # define WHERE(SECTION, NEXT)                                          \