]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
dwarflint: Extract CU header loading into pass of its own
authorPetr Machata <pmachata@redhat.com>
Fri, 20 Nov 2009 19:39:49 +0000 (20:39 +0100)
committerPetr Machata <pmachata@redhat.com>
Wed, 18 Aug 2010 12:55:13 +0000 (14:55 +0200)
* Use separately loaded CU headers to select a DWARF version to validate
  abbreviation table against.

src/dwarflint/check_debug_abbrev.cc
src/dwarflint/check_debug_info.cc
src/dwarflint/checks-low.hh
src/dwarflint/tables.cc
src/dwarflint/tables.h

index f72b39d6369f3c4af9e429c81bec7141c6cffb5f..246904574b7693c7fec4c9d835cbc7549f9f9c4d 100644 (file)
@@ -110,13 +110,6 @@ namespace
 check_debug_abbrev::check_debug_abbrev (dwarflint &lint)
   : _m_sec_abbr (lint.check (_m_sec_abbr))
 {
-  // xxx Hmm, we need to know a dwarf version to consider which
-  // attributes are legal for DW_AT_sibling.  But there's no way to
-  // get it, we need to parse abbrevs first to parse info.  We could
-  // peek to info to get CU version/table offset mapping though, but
-  // for the time being, just take version 2.
-  dwarf_version_h ver = get_dwarf_version (2);
-
   read_ctx ctx;
   read_ctx_init (&ctx, _m_sec_abbr->sect.data,
                 _m_sec_abbr->file.other_byte_order);
@@ -124,6 +117,17 @@ check_debug_abbrev::check_debug_abbrev (dwarflint &lint)
   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)
@@ -203,6 +207,48 @@ check_debug_abbrev::check_debug_abbrev (dwarflint &lint)
 
          where_reset_1 (&where, abbr_off);
          where_reset_2 (&where, abbr_off);
+
+         // 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);
        }
 
       struct abbrev *original = abbrev_table_find_abbrev (section, abbr_code);
index 2870d7444e1ef6e4a191c2a64c139d856ace9263..85b927b6fd4a2c83c52a80c2611b84a723b762d8 100644 (file)
@@ -115,8 +115,6 @@ namespace
     std::vector <cu_head> ret;
     while (!read_ctx_eof (&ctx))
       {
-       std::cout << "head " << read_ctx_get_offset (&ctx)
-                 << ' ' << pri::hex (read_ctx_get_offset (&ctx)) << std::endl;
        const unsigned char *cu_begin = ctx.ptr;
        struct where where = WHERE (sec_info, NULL);
        where_reset_1 (&where, read_ctx_get_offset (&ctx));
@@ -257,8 +255,6 @@ namespace
        return false;
       }
 
-    abbrevs->used = true;
-
     /* Read DIEs.  */
     struct ref_record local_die_refs;
     WIPE (local_die_refs);
@@ -284,7 +280,8 @@ namespace
                         struct sec *sec,
                         struct abbrev_table *abbrev_chain,
                         Elf_Data *strings,
-                        struct cu_coverage *cu_coverage)
+                        struct cu_coverage *cu_coverage,
+                        std::vector <cu_head> const &cu_headers)
   {
     struct ref_record die_refs;
     WIPE (die_refs);
@@ -300,8 +297,6 @@ namespace
       }
 
     struct relocation_data *reloc = sec->rel.size > 0 ? &sec->rel : NULL;
-    // xxx temporary static xxx
-    static std::vector <cu_head> cu_headers = read_info_headers (file, sec, reloc);
     if (reloc != NULL)
       relocation_reset (reloc);
 
@@ -311,7 +306,6 @@ namespace
         it != cu_headers.end (); ++it)
       {
        cu_head const &head = *it;
-       std::cout << "read " << pri::hex (head.offset) << std::endl;
        where const &where = head.where;
        struct cu *cur = (cu *)xcalloc (1, sizeof (*cur));
        cur->head = &head;
@@ -367,21 +361,12 @@ namespace
           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");
-         }
+         if (abbrevs->used && !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");
       }
 
 
@@ -426,19 +411,28 @@ namespace
   }
 }
 
+read_cu_headers::read_cu_headers (dwarflint &lint)
+  : _m_sec_info (lint.check (_m_sec_info))
+  , cu_headers (read_info_headers (&_m_sec_info->file,
+                                  &_m_sec_info->sect,
+                                  _m_sec_info->reldata ()))
+{
+}
+
 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))
+  , _m_cu_headers (lint.check (_m_cu_headers))
 {
   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);
+     _m_sec_str->sect.data, &cu_cov,
+     _m_cu_headers->cu_headers);
 
   if (chain == NULL)
     throw check_base::failed ();
index 9f3655842d013a4a959f08e76db9c6d123988626..5a7b4ba1ae55cfa6829c3113e91b2e36a02a4d2c 100644 (file)
@@ -18,6 +18,11 @@ public:
   sec &sect;
   elf_file &file;
   section_base (dwarflint &lint, section_id secid);
+
+  relocation_data *reldata () const
+  {
+    return sect.rel.size > 0 ? &sect.rel : NULL;
+  }
 };
 
 template<section_id sec_id>
@@ -31,10 +36,23 @@ public:
   {}
 };
 
+/** The pass for reading basic .debug_info data -- the layout of
+    sections and their headers.  */
+class read_cu_headers
+  : public check<read_cu_headers>
+{
+  section<sec_info> *_m_sec_info;
+
+public:
+  std::vector<cu_head> const cu_headers;
+  explicit read_cu_headers (dwarflint &lint);
+};
+
 class check_debug_abbrev
   : public check<check_debug_abbrev>
 {
   section<sec_abbrev> *_m_sec_abbr;
+
   bool check_no_abbreviations () const;
 
 public:
@@ -53,6 +71,7 @@ class check_debug_info
   section<sec_abbrev> *_m_sec_abbrev;
   section<sec_str> *_m_sec_str;
   check_debug_abbrev *_m_abbrevs;
+  read_cu_headers *_m_cu_headers;
 
 public:
   // The check pass adds all low_pc/high_pc ranges loaded from DIE
index c9e9cf06abd9cb9b8de31253e0baf6fd90537f5b..3b3d8e6f0d31036fe5c14f46d976d302c591195f 100644 (file)
@@ -376,6 +376,12 @@ get_dwarf_version (unsigned version)
     };
 }
 
+dwarf_version_h
+get_latest_dwarf_version ()
+{
+  return &dwarf4;
+}
+
 bool
 dwver_form_valid (dwarf_version const *ver, int form)
 {
index f5f36bf3a15fa7287d9451b3cf0422abcbd73b2e..7bfe2d93272e72222a50bab6dfa7834de63fa7b9 100644 (file)
@@ -40,6 +40,9 @@ extern "C"
   dwarf_version_h get_dwarf_version (unsigned version)
     __attribute__ ((pure));
 
+  dwarf_version_h get_latest_dwarf_version ()
+    __attribute__ ((pure));
+
   bool dwver_form_valid (dwarf_version_h ver, int form);
 
   bool dwver_form_allowed (dwarf_version_h ver, int attr, int form);