]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
dwarflint: Make abbrev table map const
authorPetr Machata <pmachata@redhat.com>
Mon, 30 Nov 2009 07:57:01 +0000 (08:57 +0100)
committerPetr Machata <pmachata@redhat.com>
Wed, 18 Aug 2010 12:55:14 +0000 (14:55 +0200)
src/dwarflint/check_debug_abbrev.cc
src/dwarflint/check_debug_info.cc
src/dwarflint/checks-low.hh
src/dwarflint/low.h

index 246904574b7693c7fec4c9d835cbc7549f9f9c4d..68d3f2223bf8f818cd2fb4a5452aac930dfc4659 100644 (file)
@@ -52,7 +52,8 @@ abbrev_table_free (struct abbrev_table *abbr)
 }
 
 struct abbrev *
-abbrev_table_find_abbrev (struct abbrev_table *abbrevs, uint64_t abbrev_code)
+abbrev_table_find_abbrev (struct abbrev_table const *abbrevs,
+                         uint64_t abbrev_code)
 {
   size_t a = 0;
   size_t b = abbrevs->size;
@@ -74,18 +75,6 @@ abbrev_table_find_abbrev (struct abbrev_table *abbrevs, uint64_t abbrev_code)
   return NULL;
 }
 
-bool
-check_debug_abbrev::check_no_abbreviations () const
-{
-  bool ret = abbrevs.begin () == abbrevs.end ();
-  if (ret)
-    {
-      where wh = WHERE (sec_abbrev, NULL);
-      wr_error (&wh, ": no abbreviations.\n");
-    }
-  return ret;
-}
-
 namespace
 {
   struct cmp_abbrev
@@ -105,353 +94,376 @@ namespace
       << pri::attr (name) << " with invalid form "
       << pri::form (form) << '.' << std::endl;
   }
-}
-
-check_debug_abbrev::check_debug_abbrev (dwarflint &lint)
-  : _m_sec_abbr (lint.check (_m_sec_abbr))
-{
-  read_ctx ctx;
-  read_ctx_init (&ctx, _m_sec_abbr->sect.data,
-                _m_sec_abbr->file.other_byte_order);
-
-  struct abbrev_table *section = NULL;
-  uint64_t first_attr_off = 0;
-  struct where where = WHERE (sec_abbrev, NULL);
-
-  // Tolerate failure here.
-  read_cu_headers *cu_headers = lint.toplev_check<read_cu_headers> ();
-  dwarf_version_h ver = NULL;
-  if (cu_headers == NULL)
-    {
-      wr_error (where)
-       << "couldn't get CU header info; assuming CUs are of latest DWARF flavor."
-       << std::endl;
-      ver = get_latest_dwarf_version ();
-    }
-  where.addr1 = 0;
-
-  while (true)
-    {
-      /* If we get EOF at this point, either the CU was improperly
-        terminated, or there were no data to begin with.  */
-      if (read_ctx_eof (&ctx))
-       {
-         if (!check_no_abbreviations ())
-           wr_error (&where, ": missing zero to mark end-of-table.\n");
-         break;
-       }
 
-      uint64_t abbr_off;
-      uint64_t abbr_code;
+  bool
+  check_no_abbreviations (check_debug_abbrev::abbrev_map const &abbrevs)
+  {
+    bool ret = abbrevs.begin () == abbrevs.end ();
+    if (ret)
       {
-       uint64_t prev_abbr_off = (uint64_t)-1;
-       uint64_t prev_abbr_code = (uint64_t)-1;
-       uint64_t zero_seq_off = (uint64_t)-1;
+       where wh = WHERE (sec_abbrev, NULL);
+       wr_error (&wh, ": no abbreviations.\n");
+      }
+    return ret;
+  }
 
-       do
-         {
-           abbr_off = read_ctx_get_offset (&ctx);
-           where_reset_2 (&where, abbr_off);
+  check_debug_abbrev::abbrev_map
+  load_debug_abbrev (dwarflint &lint,
+                    struct sec &sect,
+                    elf_file &file)
+  {
+    check_debug_abbrev::abbrev_map abbrevs;
 
-           /* Abbreviation code.  */
-           if (!checked_read_uleb128 (&ctx, &abbr_code, &where, "abbrev code"))
-             throw check_base::failed ();
+    read_ctx ctx;
+    read_ctx_init (&ctx, sect.data, file.other_byte_order);
 
-           /* Note: we generally can't tell the difference between
-              empty table and (excessive) padding.  But NUL byte(s)
-              at the very beginning of section are almost certainly
-              the first case.  */
-           if (zero_seq_off == (uint64_t)-1
-               && abbr_code == 0
-               && (prev_abbr_code == 0
-                   || abbrevs.empty ()))
-             zero_seq_off = abbr_off;
-
-           if (abbr_code != 0)
-             break;
-           else
-             section = NULL;
-
-           prev_abbr_code = abbr_code;
-           prev_abbr_off = abbr_off;
-         }
-       while (!read_ctx_eof (&ctx)
-              /* On EOF, shift the offset so that beyond-EOF
-                 end-position is printed for padding warning.
-                 Necessary as our end position is exclusive.  */
-              || ((abbr_off += 1), false));
+    struct abbrev_table *section = NULL;
+    uint64_t first_attr_off = 0;
+    struct where where = WHERE (sec_abbrev, NULL);
 
-       if (zero_seq_off != (uint64_t)-1)
+    // Tolerate failure here.
+    read_cu_headers *cu_headers = lint.toplev_check<read_cu_headers> ();
+    dwarf_version_h ver = NULL;
+    if (cu_headers == NULL)
+      {
+       wr_error (where)
+         << "couldn't load CU headers; assuming CUs are of latest DWARF flavor."
+         << std::endl;
+       ver = get_latest_dwarf_version ();
+      }
+    where.addr1 = 0;
+
+    while (true)
+      {
+       /* If we get EOF at this point, either the CU was improperly
+          terminated, or there were no data to begin with.  */
+       if (read_ctx_eof (&ctx))
          {
-           struct where wh = WHERE (where.section, NULL);
-           wr_message_padding_0 (mc_abbrevs | mc_header,
-                                 &wh, zero_seq_off, abbr_off);
+           if (!check_no_abbreviations (abbrevs))
+             wr_error (&where, ": missing zero to mark end-of-table.\n");
+           break;
          }
-      }
 
-      if (read_ctx_eof (&ctx))
+       uint64_t abbr_off;
+       uint64_t abbr_code;
        {
-         /* It still may have been empty.  */
-         check_no_abbreviations ();
-         break;
-       }
+         uint64_t prev_abbr_off = (uint64_t)-1;
+         uint64_t prev_abbr_code = (uint64_t)-1;
+         uint64_t zero_seq_off = (uint64_t)-1;
 
-      /* OK, we got some genuine abbreviation.  See if we need to
-        allocate a new section.  */
-      if (section == NULL)
-       {
-         abbrev_table t;
-         WIPE (t);
-         section = &abbrevs.insert (std::make_pair (abbr_off, t)).first->second;
-         section->offset = abbr_off;
+         do
+           {
+             abbr_off = read_ctx_get_offset (&ctx);
+             where_reset_2 (&where, abbr_off);
+
+             /* Abbreviation code.  */
+             if (!checked_read_uleb128 (&ctx, &abbr_code, &where, "abbrev code"))
+               throw check_base::failed ();
+
+             /* Note: we generally can't tell the difference between
+                empty table and (excessive) padding.  But NUL byte(s)
+                at the very beginning of section are almost certainly
+                the first case.  */
+             if (zero_seq_off == (uint64_t)-1
+                 && abbr_code == 0
+                 && (prev_abbr_code == 0
+                     || abbrevs.empty ()))
+               zero_seq_off = abbr_off;
+
+             if (abbr_code != 0)
+               break;
+             else
+               section = NULL;
 
-         where_reset_1 (&where, abbr_off);
-         where_reset_2 (&where, abbr_off);
+             prev_abbr_code = abbr_code;
+             prev_abbr_off = abbr_off;
+           }
+         while (!read_ctx_eof (&ctx)
+                /* On EOF, shift the offset so that beyond-EOF
+                   end-position is printed for padding warning.
+                   Necessary as our end position is exclusive.  */
+                || ((abbr_off += 1), false));
 
-         // Find CU that uses this abbrev table, so that we know what
-         // version to validate against.
-         if (cu_headers != NULL)
+         if (zero_seq_off != (uint64_t)-1)
            {
-             ver = NULL;
-             cu_head const *other_head = NULL;
-             for (std::vector <cu_head>::const_iterator it
-                    = cu_headers->cu_headers.begin ();
-                  it != cu_headers->cu_headers.end (); ++it)
-               if (it->abbrev_offset == abbr_off)
-                 {
-                   section->used = true;
-                   dwarf_version_h nver = get_dwarf_version (it->version);
-                   if (ver == NULL)
-                     ver = nver;
-                   else if (nver != ver)
-                     {
-                       wr_error (it->where)
-                         << " and " << other_head->where << " both use "
-                         << where << ", but each has a different version ("
-                         << it->version << " vs. " << other_head->version
-                         << ")." << std::endl;
-
-                       // Arbitrarily pick newer version.
-                       if (it->version > other_head->version)
-                         ver = nver;
-                     }
-
-                   other_head = &*it;
-                 }
-
-             if (ver == NULL)
-               {
-                 // This is hard error, we can't validate abbrev
-                 // table without knowing what version to use.
-                 wr_error (where)
-                   << "abbreviation table is never used." << std::endl;
-                 ver = get_latest_dwarf_version ();
-               }
+             struct where wh = WHERE (where.section, NULL);
+             wr_message_padding_0 (mc_abbrevs | mc_header,
+                                   &wh, zero_seq_off, abbr_off);
            }
-         assert (ver != NULL);
        }
 
-      struct abbrev *original = abbrev_table_find_abbrev (section, abbr_code);
-      if (unlikely (original != NULL))
-       wr_error (where)
-         << "duplicate abbrev code " << abbr_code
-         << "; already defined at " << original->where << '.' << std::endl;
+       if (read_ctx_eof (&ctx))
+         {
+           /* It still may have been empty.  */
+           check_no_abbreviations (abbrevs);
+           break;
+         }
 
-      struct abbrev fake;
-      struct abbrev *cur;
-      /* Don't actually save this abbrev if it's duplicate.  */
-      if (likely (original == NULL))
-       {
-         REALLOC (section, abbr);
-         cur = section->abbr + section->size++;
-       }
-      else
-       cur = &fake;
-      WIPE (*cur);
+       /* OK, we got some genuine abbreviation.  See if we need to
+          allocate a new section.  */
+       if (section == NULL)
+         {
+           abbrev_table t;
+           WIPE (t);
+           section = &abbrevs.insert (std::make_pair (abbr_off, t)).first->second;
+           section->offset = abbr_off;
 
-      cur->code = abbr_code;
-      cur->where = where;
+           where_reset_1 (&where, abbr_off);
+           where_reset_2 (&where, abbr_off);
 
-      /* Abbreviation tag.  */
-      uint64_t abbr_tag;
-      if (!checked_read_uleb128 (&ctx, &abbr_tag, &where, "abbrev tag"))
-       throw check_base::failed ();
+           // Find CU that uses this abbrev table, so that we know what
+           // version to validate against.
+           if (cu_headers != NULL)
+             {
+               ver = NULL;
+               cu_head const *other_head = NULL;
+               for (std::vector <cu_head>::const_iterator it
+                      = cu_headers->cu_headers.begin ();
+                    it != cu_headers->cu_headers.end (); ++it)
+                 if (it->abbrev_offset == abbr_off)
+                   {
+                     section->used = true;
+                     dwarf_version_h nver = get_dwarf_version (it->version);
+                     if (ver == NULL)
+                       ver = nver;
+                     else if (nver != ver)
+                       {
+                         wr_error (it->where)
+                           << " and " << other_head->where << " both use "
+                           << where << ", but each has a different version ("
+                           << it->version << " vs. " << other_head->version
+                           << ")." << std::endl;
+
+                         // Arbitrarily pick newer version.
+                         if (it->version > other_head->version)
+                           ver = nver;
+                       }
+
+                     other_head = &*it;
+                   }
+
+               if (ver == NULL)
+                 {
+                   // This is hard error, we can't validate abbrev
+                   // table without knowing what version to use.
+                   wr_error (where)
+                     << "abbreviation table is never used." << std::endl;
+                   ver = get_latest_dwarf_version ();
+                 }
+             }
+           assert (ver != NULL);
+         }
 
-      if (abbr_tag > DW_TAG_hi_user)
-       {
+       struct abbrev *original = abbrev_table_find_abbrev (section, abbr_code);
+       if (unlikely (original != NULL))
          wr_error (where)
-           << "invalid abbrev tag " << pri::hex (abbr_tag)
-           << '.' << std::endl;
-         throw check_base::failed ();
-       }
-      cur->tag = (typeof (cur->tag))abbr_tag;
+           << "duplicate abbrev code " << abbr_code
+           << "; already defined at " << original->where << '.' << std::endl;
 
-      /* Abbreviation has_children.  */
-      uint8_t has_children;
-      if (!read_ctx_read_ubyte (&ctx, &has_children))
-       {
-         wr_error (&where, ": can't read abbrev has_children.\n");
-         throw check_base::failed ();
-       }
+       struct abbrev fake;
+       struct abbrev *cur;
+       /* Don't actually save this abbrev if it's duplicate.  */
+       if (likely (original == NULL))
+         {
+           REALLOC (section, abbr);
+           cur = section->abbr + section->size++;
+         }
+       else
+         cur = &fake;
+       WIPE (*cur);
 
-      if (has_children != DW_CHILDREN_no
-         && has_children != DW_CHILDREN_yes)
-       {
-         wr_error (where)
-           << "invalid has_children value " << pri::hex (cur->has_children)
-           << '.' << std::endl;
+       cur->code = abbr_code;
+       cur->where = where;
+
+       /* Abbreviation tag.  */
+       uint64_t abbr_tag;
+       if (!checked_read_uleb128 (&ctx, &abbr_tag, &where, "abbrev tag"))
          throw check_base::failed ();
-       }
-      cur->has_children = has_children == DW_CHILDREN_yes;
-
-      bool null_attrib;
-      uint64_t sibling_attr = 0;
-      bool low_pc = false;
-      bool high_pc = false;
-      bool ranges = false;
-      do
-       {
-         uint64_t attr_off = read_ctx_get_offset (&ctx);
-         uint64_t attrib_name, attrib_form;
-         if (first_attr_off == 0)
-           first_attr_off = attr_off;
-         /* Shift to match elfutils reporting.  */
-         where_reset_3 (&where, attr_off - first_attr_off);
-
-         /* Load attribute name and form.  */
-         if (!checked_read_uleb128 (&ctx, &attrib_name, &where,
-                                    "attribute name"))
+
+       if (abbr_tag > DW_TAG_hi_user)
+         {
+           wr_error (where)
+             << "invalid abbrev tag " << pri::hex (abbr_tag)
+             << '.' << std::endl;
            throw check_base::failed ();
+         }
+       cur->tag = (typeof (cur->tag))abbr_tag;
 
-         if (!checked_read_uleb128 (&ctx, &attrib_form, &where,
-                                    "attribute form"))
+       /* Abbreviation has_children.  */
+       uint8_t has_children;
+       if (!read_ctx_read_ubyte (&ctx, &has_children))
+         {
+           wr_error (&where, ": can't read abbrev has_children.\n");
            throw check_base::failed ();
+         }
 
-         null_attrib = attrib_name == 0 && attrib_form == 0;
+       if (has_children != DW_CHILDREN_no
+           && has_children != DW_CHILDREN_yes)
+         {
+           wr_error (where)
+             << "invalid has_children value " << pri::hex (cur->has_children)
+             << '.' << std::endl;
+           throw check_base::failed ();
+         }
+       cur->has_children = has_children == DW_CHILDREN_yes;
 
-         /* Now if both are zero, this was the last attribute.  */
-         if (!null_attrib)
-           {
-             /* Otherwise validate name and form.  */
-             if (attrib_name > DW_AT_hi_user)
-               {
-                 wr_error (where)
-                   << "invalid name " << pri::hex (attrib_name)
-                   << '.' << std::endl;
-                 throw check_base::failed ();
-               }
+       bool null_attrib;
+       uint64_t sibling_attr = 0;
+       bool low_pc = false;
+       bool high_pc = false;
+       bool ranges = false;
+       do
+         {
+           uint64_t attr_off = read_ctx_get_offset (&ctx);
+           uint64_t attrib_name, attrib_form;
+           if (first_attr_off == 0)
+             first_attr_off = attr_off;
+           /* Shift to match elfutils reporting.  */
+           where_reset_3 (&where, attr_off - first_attr_off);
+
+           /* Load attribute name and form.  */
+           if (!checked_read_uleb128 (&ctx, &attrib_name, &where,
+                                      "attribute name"))
+             throw check_base::failed ();
 
-             if (!ver->form_allowed (attrib_form))
-               {
-                 wr_error (where)
-                   << "invalid form " << pri::hex (attrib_form)
-                   << '.' << std::endl;
-                 throw check_base::failed ();
-               }
-           }
+           if (!checked_read_uleb128 (&ctx, &attrib_form, &where,
+                                      "attribute form"))
+             throw check_base::failed ();
 
-         REALLOC (cur, attribs);
+           null_attrib = attrib_name == 0 && attrib_form == 0;
 
-         struct abbrev_attrib *acur = cur->attribs + cur->size++;
-         WIPE (*acur);
+           /* Now if both are zero, this was the last attribute.  */
+           if (!null_attrib)
+             {
+               /* Otherwise validate name and form.  */
+               if (attrib_name > DW_AT_hi_user)
+                 {
+                   wr_error (where)
+                     << "invalid name " << pri::hex (attrib_name)
+                     << '.' << std::endl;
+                   throw check_base::failed ();
+                 }
 
-         /* We do structural checking of sibling attribute, so make
-            sure our assumptions in actual DIE-loading code are
-            right.  We expect at most one DW_AT_sibling attribute,
-            with form from reference class, but only CU-local, not
-            DW_FORM_ref_addr.  */
-         if (attrib_name == DW_AT_sibling)
-           {
-             if (sibling_attr != 0)
-               wr_error (where)
-                 << "another DW_AT_sibling attribute in one abbreviation "
-                 << "(first was " << pri::hex (sibling_attr) << ")."
-                 << std::endl;
-             else
-               {
-                 assert (attr_off > 0);
-                 sibling_attr = attr_off;
-
-                 if (!cur->has_children)
-                   wr_message (where,
-                               cat (mc_die_rel, mc_acc_bloat, mc_impact_1))
-                     << "excessive DW_AT_sibling attribute at childless abbrev."
-                     << std::endl;
-               }
+               if (!ver->form_allowed (attrib_form))
+                 {
+                   wr_error (where)
+                     << "invalid form " << pri::hex (attrib_form)
+                     << '.' << std::endl;
+                   throw check_base::failed ();
+                 }
+             }
 
-             switch (check_sibling_form (ver, attrib_form))
-               {
-               case -1:
-                 wr_message (where, cat (mc_die_rel, mc_impact_2))
-                   << "DW_AT_sibling attribute with form DW_FORM_ref_addr."
-                   << std::endl;
-                 break;
+           REALLOC (cur, attribs);
+
+           struct abbrev_attrib *acur = cur->attribs + cur->size++;
+           WIPE (*acur);
 
-               case -2:
+           /* We do structural checking of sibling attribute, so make
+              sure our assumptions in actual DIE-loading code are
+              right.  We expect at most one DW_AT_sibling attribute,
+              with form from reference class, but only CU-local, not
+              DW_FORM_ref_addr.  */
+           if (attrib_name == DW_AT_sibling)
+             {
+               if (sibling_attr != 0)
                  wr_error (where)
-                   << "DW_AT_sibling attribute with non-reference form "
-                   << pri::form (attrib_form) << '.' << std::endl;
-               };
-           }
-         /* Similar for DW_AT_location and friends.  */
-         else if (is_location_attrib (attrib_name))
-           {
-             if (!dwver_form_allowed (ver, attrib_name, attrib_form))
-               complain_invalid_form (where, attrib_name, attrib_form,
-                                      "location attribute");
-           }
-         /* Similar for DW_AT_ranges.  */
-         else if (attrib_name == DW_AT_ranges
-                  || attrib_name == DW_AT_stmt_list)
-           {
-             if (attrib_form != DW_FORM_data4
-                 && attrib_form != DW_FORM_data8
-                 && attrib_form != DW_FORM_sec_offset
-                 && attrib_form != DW_FORM_indirect)
-               complain_invalid_form (where, attrib_name, attrib_form);
-             if (attrib_name == DW_AT_ranges)
-               ranges = true;
-           }
-         /* Similar for DW_AT_{low,high}_pc, plus also make sure we
-            don't see high_pc without low_pc.  */
-         else if (attrib_name == DW_AT_low_pc
-                  || attrib_name == DW_AT_high_pc)
-           {
-             if (attrib_form != DW_FORM_addr
-                 && attrib_form != DW_FORM_ref_addr)
-               complain_invalid_form (where, attrib_name, attrib_form);
-
-             if (attrib_name == DW_AT_low_pc)
-               low_pc = true;
-             else if (attrib_name == DW_AT_high_pc)
-               high_pc = true;
-           }
+                   << "another DW_AT_sibling attribute in one abbreviation "
+                   << "(first was " << pri::hex (sibling_attr) << ")."
+                   << std::endl;
+               else
+                 {
+                   assert (attr_off > 0);
+                   sibling_attr = attr_off;
+
+                   if (!cur->has_children)
+                     wr_message (where,
+                                 cat (mc_die_rel, mc_acc_bloat, mc_impact_1))
+                       << "excessive DW_AT_sibling attribute at childless abbrev."
+                       << std::endl;
+                 }
 
-         acur->name = attrib_name;
-         acur->form = attrib_form;
-         acur->where = where;
-       }
-      while (!null_attrib);
+               switch (check_sibling_form (ver, attrib_form))
+                 {
+                 case -1:
+                   wr_message (where, cat (mc_die_rel, mc_impact_2))
+                     << "DW_AT_sibling attribute with form DW_FORM_ref_addr."
+                     << std::endl;
+                   break;
+
+                 case -2:
+                   wr_error (where)
+                     << "DW_AT_sibling attribute with non-reference form "
+                     << pri::form (attrib_form) << '.' << std::endl;
+                 };
+             }
+           /* Similar for DW_AT_location and friends.  */
+           else if (is_location_attrib (attrib_name))
+             {
+               if (!dwver_form_allowed (ver, attrib_name, attrib_form))
+                 complain_invalid_form (where, attrib_name, attrib_form,
+                                        "location attribute");
+             }
+           /* Similar for DW_AT_ranges.  */
+           else if (attrib_name == DW_AT_ranges
+                    || attrib_name == DW_AT_stmt_list)
+             {
+               if (attrib_form != DW_FORM_data4
+                   && attrib_form != DW_FORM_data8
+                   && attrib_form != DW_FORM_sec_offset
+                   && attrib_form != DW_FORM_indirect)
+                 complain_invalid_form (where, attrib_name, attrib_form);
+               if (attrib_name == DW_AT_ranges)
+                 ranges = true;
+             }
+           /* Similar for DW_AT_{low,high}_pc, plus also make sure we
+              don't see high_pc without low_pc.  */
+           else if (attrib_name == DW_AT_low_pc
+                    || attrib_name == DW_AT_high_pc)
+             {
+               if (attrib_form != DW_FORM_addr
+                   && attrib_form != DW_FORM_ref_addr)
+                 complain_invalid_form (where, attrib_name, attrib_form);
+
+               if (attrib_name == DW_AT_low_pc)
+                 low_pc = true;
+               else if (attrib_name == DW_AT_high_pc)
+                 high_pc = true;
+             }
+
+           acur->name = attrib_name;
+           acur->form = attrib_form;
+           acur->where = where;
+         }
+       while (!null_attrib);
 
-      where_reset_2 (&where, where.addr2); // drop addr 3
-      if (high_pc && !low_pc)
-       wr_error (where)
-         << "the abbrev has DW_AT_high_pc without also having DW_AT_low_pc."
-         << std::endl;
-      else if (high_pc && ranges)
-       wr_error (where)
-         << "the abbrev has DW_AT_high_pc & DW_AT_low_pc, "
-         << "but also has DW_AT_ranges." << std::endl;
-    }
+       where_reset_2 (&where, where.addr2); // drop addr 3
+       if (high_pc && !low_pc)
+         wr_error (where)
+           << "the abbrev has DW_AT_high_pc without also having DW_AT_low_pc."
+           << std::endl;
+       else if (high_pc && ranges)
+         wr_error (where)
+           << "the abbrev has DW_AT_high_pc & DW_AT_low_pc, "
+           << "but also has DW_AT_ranges." << std::endl;
+      }
 
-  abbrev_table *last = NULL;
-  for (abbrev_map::iterator it = abbrevs.begin (); it != abbrevs.end (); ++it)
-    {
-      std::sort (it->second.abbr, it->second.abbr + it->second.size,
-                cmp_abbrev ());
-      if (last != NULL)
-       last->next = &it->second;
-      last = &it->second;
-    }
+    abbrev_table *last = NULL;
+    for (check_debug_abbrev::abbrev_map::iterator it = abbrevs.begin ();
+        it != abbrevs.end (); ++it)
+      {
+       std::sort (it->second.abbr, it->second.abbr + it->second.size,
+                  cmp_abbrev ());
+       if (last != NULL)
+         last->next = &it->second;
+       last = &it->second;
+      }
+
+    return abbrevs;
+  }
 }
 
+check_debug_abbrev::check_debug_abbrev (dwarflint &lint)
+  : _m_sec_abbr (lint.check (_m_sec_abbr))
+  , abbrevs (load_debug_abbrev (lint, _m_sec_abbr->sect, _m_sec_abbr->file))
+{
+}
index dda8b5a131a0a04b41c61a5d7c397e56774ef66e..f4b12237c1c6ff6dde622ccd0f4ca42da5785c4c 100644 (file)
@@ -35,6 +35,7 @@
 
 #include <cassert>
 #include <sstream>
+#include <algorithm>
 #include "../libdw/dwarf.h"
 
 #include "messages.h"
@@ -96,8 +97,8 @@ namespace
          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.  */
+              anyway, perhaps local reference could be formed on
+              smaller 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",
@@ -426,7 +427,7 @@ namespace
                  struct elf_file *file,
                  struct read_ctx *ctx,
                  struct cu *cu,
-                 struct abbrev_table *abbrevs,
+                 struct abbrev_table const *abbrevs,
                  Elf_Data *strings,
                  struct ref_record *local_die_refs,
                  struct coverage *strings_coverage,
@@ -954,55 +955,56 @@ namespace
 
     return got_die ? 1 : 0;
   }
+}
 
-  bool
-  check_cu_structural (struct elf_file *file,
-                      struct read_ctx *ctx,
-                      struct cu *const cu,
-                      check_debug_abbrev::abbrev_map &abbrev_tables,
-                      Elf_Data *strings,
-                      struct coverage *strings_coverage,
-                      struct relocation_data *reloc,
-                      struct cu_coverage *cu_coverage)
-  {
-    if (dump_die_offsets)
-      fprintf (stderr, "%s: CU starts\n", where_fmt (&cu->head->where, NULL));
-    bool retval = true;
+bool
+check_debug_info::check_cu_structural (struct elf_file *file,
+                                      struct read_ctx *ctx,
+                                      struct cu *const cu,
+                                      Elf_Data *strings,
+                                      struct coverage *strings_coverage,
+                                      struct relocation_data *reloc,
+                                      struct cu_coverage *cu_coverage)
+{
+  check_debug_abbrev::abbrev_map const &abbrev_tables = _m_abbrevs->abbrevs;
 
-    dwarf_version_h ver = get_dwarf_version (cu->head->version);
-    assert (ver != NULL);
+  if (dump_die_offsets)
+    fprintf (stderr, "%s: CU starts\n", where_fmt (&cu->head->where, NULL));
+  bool retval = true;
 
-    /* Look up Abbrev table for this CU.  */
-    check_debug_abbrev::abbrev_map::iterator abbrev_it
-      = abbrev_tables.find (cu->head->abbrev_offset);
-    if (abbrev_it == abbrev_tables.end ())
-      {
-       wr_error (cu->head->where)
-         << "couldn't find abbrev section with offset "
-         << pri::addr (cu->head->abbrev_offset) << '.' << std::endl;
-       return false;
-      }
-    struct abbrev_table &abbrevs = abbrev_it->second;
+  dwarf_version_h ver = get_dwarf_version (cu->head->version);
+  assert (ver != NULL);
+
+  /* Look up Abbrev table for this CU.  */
+  check_debug_abbrev::abbrev_map::const_iterator abbrev_it
+    = abbrev_tables.find (cu->head->abbrev_offset);
+  if (abbrev_it == abbrev_tables.end ())
+    {
+      wr_error (cu->head->where)
+       << "couldn't find abbrev section with offset "
+       << pri::addr (cu->head->abbrev_offset) << '.' << std::endl;
+      return false;
+    }
+  struct abbrev_table const &abbrevs = abbrev_it->second;
 
-    /* Read DIEs.  */
-    struct ref_record local_die_refs;
-    WIPE (local_die_refs);
+  /* Read DIEs.  */
+  struct ref_record local_die_refs;
+  WIPE (local_die_refs);
 
-    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,
-                       cu_coverage) < 0)
-      {
-       abbrevs.skip_check = true;
-       retval = false;
-      }
-    else if (!check_die_references (cu, &local_die_refs))
+  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,
+                     cu_coverage) < 0)
+    {
+      _m_abbr_skip.push_back (abbrevs.offset);
       retval = false;
+    }
+  else if (!check_die_references (cu, &local_die_refs))
+    retval = false;
 
-    ref_record_free (&local_die_refs);
-    return retval;
-  }
+  ref_record_free (&local_die_refs);
+  return retval;
 }
 
 read_cu_headers::read_cu_headers (dwarflint &lint)
@@ -1015,10 +1017,10 @@ read_cu_headers::read_cu_headers (dwarflint &lint)
 
 struct cu *
 check_debug_info::check_info_structural (struct elf_file *file,
-                                        struct sec *sec,
                                         Elf_Data *strings)
 {
   std::vector <cu_head> const &cu_headers = _m_cu_headers->cu_headers;
+  sec &sec = _m_sec_info->sect;
   struct ref_record die_refs;
   WIPE (die_refs);
 
@@ -1032,12 +1034,12 @@ check_debug_info::check_info_structural (struct elf_file *file,
       strings_coverage = &strings_coverage_mem;
     }
 
-  struct relocation_data *reloc = sec->rel.size > 0 ? &sec->rel : NULL;
+  struct relocation_data *reloc = sec.rel.size > 0 ? &sec.rel : NULL;
   if (reloc != NULL)
     relocation_reset (reloc);
 
   struct read_ctx ctx;
-  read_ctx_init (&ctx, sec->data, file->other_byte_order);
+  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)
     {
@@ -1058,7 +1060,7 @@ check_debug_info::check_info_structural (struct elf_file *file,
       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, _m_abbrevs->abbrevs,
+      if (!check_cu_structural (file, &cu_ctx, cur,
                                strings, strings_coverage, reloc,
                                &cu_cov))
        {
@@ -1091,14 +1093,16 @@ check_debug_info::check_info_structural (struct elf_file *file,
        }
       else
        /* Did we consume all the relocations?  */
-       relocation_skip_rest (&sec->rel, sec->id);
+       relocation_skip_rest (&sec.rel, sec.id);
 
       /* If we managed to read up everything, now do abbrev usage
         analysis.  */
       for (check_debug_abbrev::abbrev_map::const_iterator it
             = _m_abbrevs->abbrevs.begin ();
           it != _m_abbrevs->abbrevs.end (); ++it)
-       if (it->second.used && !it->second.skip_check)
+       if (it->second.used
+           && std::find (_m_abbr_skip.begin (), _m_abbr_skip.end (),
+                         it->first) == _m_abbr_skip.end ())
          for (size_t i = 0; i < it->second.size; ++i)
            if (!it->second.abbr[i].used)
              wr_message (it->second.abbr[i].where,
@@ -1156,8 +1160,7 @@ check_debug_info::check_debug_info (dwarflint &lint)
 {
   memset (&cu_cov, 0, sizeof (cu_cov));
 
-  cu *chain = check_info_structural (&_m_sec_info->file, &_m_sec_info->sect,
-                                    _m_sec_str->sect.data);
+  cu *chain = check_info_structural (&_m_sec_info->file, _m_sec_str->sect.data);
 
   if (chain == NULL)
     throw check_base::failed ();
index b6905d14dcdfbc3647f4fbfc1523a6647ab8de8b..87690b03e2f35496c13e48956955c5632035eeba 100644 (file)
@@ -81,14 +81,12 @@ class check_debug_abbrev
 {
   section<sec_abbrev> *_m_sec_abbr;
 
-  bool check_no_abbreviations () const;
-
 public:
-  explicit check_debug_abbrev (dwarflint &lint);
-
   // offset -> abbreviations
   typedef std::map< ::Dwarf_Off, abbrev_table> abbrev_map;
-  abbrev_map abbrevs;
+  abbrev_map const abbrevs;
+
+  explicit check_debug_abbrev (dwarflint &lint);
 };
 static reg<check_debug_abbrev> reg_debug_abbrev;
 
@@ -101,8 +99,19 @@ class check_debug_info
   check_debug_abbrev *_m_abbrevs;
   read_cu_headers *_m_cu_headers;
 
+  // Abbreviation table with that offset had user(s) that failed
+  // validation.  Check for unused abbrevs should be skipped.
+  std::vector< ::Dwarf_Off> _m_abbr_skip;
+
+  bool check_cu_structural (struct elf_file *file,
+                           struct read_ctx *ctx,
+                           struct cu *const cu,
+                           Elf_Data *strings,
+                           struct coverage *strings_coverage,
+                           struct relocation_data *reloc,
+                           struct cu_coverage *cu_coverage);
+
   struct cu *check_info_structural (elf_file *file,
-                                   struct sec *sec,
                                    Elf_Data *strings);
 
 public:
index ee345aa6d216b9638e1910b52e28a8591481cace..98612a87975e5efc4bd681385bdada9e19fc8a32 100644 (file)
@@ -88,14 +88,11 @@ extern "C"
     size_t size;
     size_t alloc;
     bool used;         /* There are CUs using this table.  */
-    bool skip_check;   /* There were errors during loading one of the
-                          CUs that use this table.  Check for unused
-                          abbrevs should be skipped.  */
   };
 
   // xxx some of that will go away
   extern void abbrev_table_free (struct abbrev_table *abbr);
-  extern struct abbrev *abbrev_table_find_abbrev (struct abbrev_table *abbrevs,
+  extern struct abbrev *abbrev_table_find_abbrev (struct abbrev_table const *abbrevs,
                                                  uint64_t abbrev_code);
   extern bool read_rel (struct elf_file *file, struct sec *sec,
                        Elf_Data *reldata, bool elf_64);