]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
dwarflint: Streamlining code
authorPetr Machata <pmachata@redhat.com>
Sat, 9 Oct 2010 18:45:04 +0000 (20:45 +0200)
committerPetr Machata <pmachata@redhat.com>
Sat, 9 Oct 2010 18:45:04 +0000 (20:45 +0200)
- Extract checks common to direct and indirect forms to
  check_debug_abbrev::check_form.
- Reading of indirect form is now done via a new function read_sc_value
  in check_debug_info.cc.  That function is also called for reading
  normal values of classes sc_value and sc_block

dwarflint/check_debug_abbrev.cc
dwarflint/check_debug_abbrev.hh
dwarflint/check_debug_info.cc
dwarflint/dwarf_version.cc
dwarflint/dwarf_version.hh
dwarflint/misc.hh

index 4d0c6dac539bb097f4992255bd1aa0890b6eb20d..fac1f4688b6ed477bfd187668650daaf648bd15b 100644 (file)
@@ -111,13 +111,14 @@ namespace
   };
 
   void
-  complain_invalid_form (where const &where, int name, int form,
-                        std::string const &specification = "")
+  complain (where const *where,
+           attribute const *attribute, form const *form,
+           bool indirect, char const *qualifier)
   {
-    wr_error (where)
-      << specification << (" "[specification.length () == 0])
-      << pri::attr (name) << " with invalid form "
-      << pri::form (form) << '.' << std::endl;
+    wr_error (*where)
+      << "attribute " << *attribute << " with " << qualifier
+      << (indirect ? " indirect" : "") << " form"
+      << *form << '.' << std::endl;
   }
 
   bool
@@ -360,61 +361,53 @@ namespace
 
            /* Now if both are zero, this was the last attribute.  */
            null_attrib = attrib_name == 0 && attrib_form == 0;
-
            attribute const *attribute = NULL;
-           form const *form = NULL;
-           if (!null_attrib)
-             {
-               /* Otherwise validate name and form.  */
-               attribute = ver->get_attribute (attrib_name);
-               if (attribute == NULL)
-                 {
-                   wr_error (where)
-                     << "invalid name " << pri::hex (attrib_name)
-                     << '.' << std::endl;
-                   failed = true;
-                   continue;
-                 }
 
-               form = ver->get_form (attrib_form);
-               if (form == NULL)
-                 {
-                   wr_error (where)
-                     << "invalid form " << pri::hex (attrib_form)
-                     << '.' << std::endl;
-                   failed = true;
-                   continue;
-                 }
+           REALLOC (cur, attribs);
 
-               if (!ver->form_allowed (attribute->name (), form->name ()))
-                 complain_invalid_form (where, attrib_name, attrib_form,
-                                        "attribute");
+           struct abbrev_attrib *acur = cur->attribs + cur->size++;
+           WIPE (*acur);
+           acur->name = attrib_name;
+           acur->form = attrib_form;
+           acur->where = where;
 
-               std::pair<std::map<unsigned, uint64_t>::iterator, bool> inserted
-                 = seen.insert (std::make_pair (attrib_name, attr_off));
-               if (!inserted.second)
-                 {
-                   wr_error (where)
-                     << "duplicate attribute " << pri::attr (attrib_name)
-                     << " (first was at " << pri::hex (inserted.first->second)
-                     << ")." << std::endl;
-                   // I think we may allow such files for high-level
-                   // consumption, so don't fail the check...
-                   if (attrib_name == DW_AT_sibling)
-                     // ... unless it's DW_AT_sibling.
-                     failed = true;
-                 }
+           if (null_attrib)
+             break;
+
+           /* Otherwise validate name and form.  */
+           attribute = ver->get_attribute (attrib_name);
+           if (attribute == NULL)
+             {
+               wr_error (where)
+                 << "invalid name " << pri::hex (attrib_name)
+                 << '.' << std::endl;
+               failed = true;
+               continue;
              }
 
-           REALLOC (cur, attribs);
+           std::pair<std::map<unsigned, uint64_t>::iterator, bool> inserted
+             = seen.insert (std::make_pair (attrib_name, attr_off));
+           if (!inserted.second)
+             {
+               wr_error (where)
+                 << "duplicate attribute " << pri::attr (attrib_name)
+                 << " (first was at " << pri::hex (inserted.first->second)
+                 << ")." << std::endl;
+               // I think we may allow such files for high-level
+               // consumption, so don't fail the check...
+               if (attrib_name == DW_AT_sibling)
+                 // ... unless it's DW_AT_sibling.
+                 failed = true;
+             }
 
-           struct abbrev_attrib *acur = cur->attribs + cur->size++;
-           WIPE (*acur);
+           form const *form = check_debug_abbrev::check_form
+             (ver, attrib_form, attribute, &where, false);
+           if (form == NULL)
+             {
+               failed = true;
+               continue;
+             }
 
-           /* We do structural checking of sibling attribute, so make
-              sure our assumptions in actual DIE-loading code are
-              right.  We expect form from reference class, but only
-              CU-local, not DW_FORM_ref_addr.  */
            if (attrib_name == DW_AT_sibling)
              {
                if (!cur->has_children)
@@ -422,35 +415,13 @@ namespace
                              cat (mc_die_rel, mc_acc_bloat, mc_impact_1))
                    << "excessive DW_AT_sibling attribute at childless abbrev."
                    << std::endl;
-
-               switch (sibling_form_suitable (ver, attrib_form))
-                 {
-                 case sfs_long:
-                   wr_message (where, cat (mc_die_rel, mc_impact_2))
-                     << "DW_AT_sibling attribute with form DW_FORM_ref_addr."
-                     << std::endl;
-                   break;
-
-                 case sfs_invalid:
-                   wr_error (where)
-                     << "DW_AT_sibling attribute with non-reference form "
-                     << pri::form (attrib_form) << '.' << std::endl;
-
-                 case sfs_ok:
-                   ;
-                 };
              }
-
-           else if (attrib_name == DW_AT_ranges)
+           if (attrib_name == DW_AT_ranges)
              ranges = true;
            else 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);
 
@@ -492,6 +463,32 @@ check_debug_abbrev::check_debug_abbrev (checkstack &stack, dwarflint &lint)
 {
 }
 
+form const *
+check_debug_abbrev::check_form (dwarf_version const *ver, int form_name,
+                               attribute const *attribute, where const *where,
+                               bool indirect)
+{
+  form const *form = ver->get_form (form_name);
+  if (form == NULL)
+    {
+      wr_error (*where)
+       << "invalid form " << pri::hex (form_name)
+       << '.' << std::endl;
+      return NULL;
+    }
+
+  if (!ver->form_allowed (attribute->name (), form_name))
+    {
+      complain (where, attribute, form, indirect, "invalid");
+      return NULL;
+    }
+  else if (attribute->name () == DW_AT_sibling
+          && sibling_form_suitable (ver, form_name) == sfs_long)
+    complain (where, attribute, form, indirect, "unsuitable");
+
+  return form;
+}
+
 check_debug_abbrev::~check_debug_abbrev ()
 {
   // xxx So using new[]/delete[] would be nicer (delete ignores
index 9d1d77824f140c0400bf6084d60ef7583b619253..bdc7f8c6ae1091ce2a81099d93ca85079fd42439 100644 (file)
@@ -29,6 +29,7 @@
 #include "checks.hh"
 #include "sections.ii"
 #include "check_debug_info.ii"
+#include "dwarf_version.ii"
 
 struct abbrev_attrib
 {
@@ -83,6 +84,12 @@ public:
   abbrev_map const abbrevs;
 
   check_debug_abbrev (checkstack &stack, dwarflint &lint);
+  static form const *check_form (dwarf_version const *ver,
+                                int form_name,
+                                attribute const *attribute,
+                                where const *where,
+                                bool indirect);
+
   ~check_debug_abbrev ();
 };
 
index 6736d64728a6b337e7fc6eea322e09e68ecde316..29afad640d33dee1573e6c0add324946e6631591 100644 (file)
@@ -495,6 +495,37 @@ namespace
     ref_record_add (&ctx->cu->decl_file_refs, value, ctx->where);
   }
 
+  /// Read value depending on the form width and storage class.
+  bool
+  read_sc_value (uint64_t *valuep, form const *form, cu const *cu,
+                read_ctx *ctx, where *wherep)
+  {
+    form_width_t width = form->width (cu);
+    switch (width)
+      {
+      case fw_0:
+       // Who knows, DW_FORM_flag_absent might turn up one day...
+       assert (form->name () == DW_FORM_flag_present);
+       *valuep = 1;
+       return true;
+
+      case fw_1:
+      case fw_2:
+      case fw_4:
+      case fw_8:
+       return read_ctx_read_var (ctx, width, valuep);
+
+      case fw_uleb:
+      case fw_sleb:
+       return checked_read_leb128 (ctx, width, valuep,
+                                   wherep, "attribute value");
+
+      case fw_unknown:
+       ;
+      }
+    UNREACHABLE;
+  }
+
   /*
     Returns:
     -1 in case of error
@@ -628,42 +659,13 @@ namespace
            if (ver->form_class (form, attribute) == cl_indirect)
              {
                uint64_t value;
-               if (!checked_read_uleb128 (ctx, &value, &where,
-                                          "indirect attribute form"))
+               if (!read_sc_value (&value, form, cu, ctx, &where))
                  return -1;
                form_name = value;
-               form = ver->get_form (form_name);
-
-               // xxx Some of what's below is probably duplicated in
-               // check_debug_abbrev.  Plus we really want to run the
-               // same checks for direct and indirect attributes.
-               // Consolidate.
-               if (!ver->form_allowed (form_name))
-                 {
-                   wr_error (where)
-                     << "invalid indirect form " << pri::hex (value)
-                     << '.' << std::endl;
-                   return -1;
-                 }
-
-               if (attribute->name () == DW_AT_sibling)
-                 switch (sibling_form_suitable (ver, form_name))
-                   {
-                   case sfs_long:
-                     wr_message (where, cat (mc_die_rel, mc_impact_2))
-                       << "DW_AT_sibling attribute with (indirect) form "
-                       "DW_FORM_ref_addr." << std::endl;
-                     break;
-
-                   case sfs_invalid:
-                     wr_error (where)
-                       << "DW_AT_sibling attribute with non-reference "
-                       "(indirect) form \"" << pri::form (value)
-                       << "\"." << std::endl;
-
-                   case sfs_ok:
-                     ;
-                   }
+               form = check_debug_abbrev::check_form
+                 (ver, form_name, attribute, &where, true);
+               if (form == NULL)
+                 return -1;
              }
 
            dw_class cls = ver->form_class (form, attribute);
@@ -682,9 +684,6 @@ namespace
            uint64_t ctx_offset = read_ctx_get_offset (ctx) + cu->head->offset;
            bool type_is_rel = file.ehdr.e_type == ET_REL;
 
-           /* Attribute value.  */
-           uint64_t value = 0;
-
            /* Whether the value should be relocated first.  Note that
               relocations are really required only in REL files, so
               missing relocations are not warned on even with
@@ -800,75 +799,46 @@ namespace
                break;
              }
 
-           /* Read value depending on the form width and storage
-              class.  */
-           form_width_t width = form->width (cu);
+           /* Attribute value.  */
+           uint64_t value;
            storage_class_t storclass = form->storage_class ();
-           switch (storclass)
+           if (storclass == sc_string)
              {
-             case sc_string:
                if (!read_ctx_read_str (ctx))
                  goto cant_read;
-               break;
+             }
+           else
+             {
+               if (!read_sc_value (&value, form, cu, ctx, &where))
+                 {
+                   // Note that for fw_uleb and fw_sleb we report the
+                   // error the second time now.
+                 cant_read:
+                   wr_error (where)
+                     << "can't read value of attribute "
+                     << *attribute << '.' << std::endl;
+                   return -1;
+                 }
 
-             case sc_block:
-             case sc_value:
-               // Read the value, or the length field if it's a block
-               // form.
-               switch (width)
+               if (storclass == sc_block)
                  {
-                 case fw_0:
-                   // who knows, DW_FORM_flag_absent might turn up one day
-                   assert (form->name () == DW_FORM_flag_present);
-                   value = 1;
-                   break;
-
-                 case fw_1:
-                 case fw_2:
-                 case fw_4:
-                 case fw_8:
-                   if (!read_ctx_read_var (ctx, width, &value))
+                   // Read & validate the block body.
+                   if (cls == cl_exprloc)
                      {
-                     cant_read:
-                       wr_error (where)
-                         << "can't read value of attribute "
-                         << pri::attr (it->name) << '.' << std::endl;
-                       return -1;
+                       uint64_t expr_start
+                         = cu->head->offset + read_ctx_get_offset (ctx);
+                       if (!check_location_expression
+                           (file, ctx, cu, expr_start, reloc, value, &where))
+                         return false;
                      }
-                   break;
-
-                 case fw_uleb:
-                 case fw_sleb:
-                   if (!checked_read_leb128 (ctx, width, &value,
-                                             &where, "attribute value"))
-                     return -1;
-                   break;
+                   else
+                     relocation_skip (reloc,
+                                      read_ctx_get_offset (ctx) + value,
+                                      &where, skip_mismatched);
 
-                 case fw_unknown:
-                   assert (!"Should never get there!");
+                   if (!read_ctx_skip (ctx, value))
+                     goto cant_read;
                  }
-
-               if (storclass != sc_block)
-                 break;
-
-               // Read & validate the block body.
-               if (cls == cl_exprloc)
-                 {
-                   uint64_t expr_start
-                     = cu->head->offset + read_ctx_get_offset (ctx);
-                   if (!check_location_expression
-                       (file, ctx, cu, expr_start, reloc, value, &where))
-                     return -1;
-                 }
-               else
-                 relocation_skip (reloc,
-                                  read_ctx_get_offset (ctx) + value,
-                                  &where, skip_mismatched);
-
-               if (!read_ctx_skip (ctx, value))
-                 goto cant_read;
-
-               break;
              }
 
            /* Relocate the value if appropriate.  */
@@ -882,6 +852,7 @@ namespace
                    << "unexpected relocation of " << pri::form (form_name)
                    << '.' << std::endl;
 
+               form_width_t width = form->width (cu);
                relocate_one (&file, reloc, rel, width, &value, &where,
                              reloc_target (form_name, it), symbolp);
 
index dc8aab37c427d883c1d208e6e00b77dfe1c8f3c1..669a5f8a6d795b87e2fe60c2a304b4f0629e6f58 100644 (file)
@@ -33,6 +33,7 @@
 #include "dwarf_4.hh"
 #include "dwarf_mips.hh"
 #include "check_debug_info.hh"
+#include "pri.hh"
 
 #include "../libdw/dwarf.h"
 #include <map>
@@ -97,6 +98,12 @@ form::width (cu const *cu) const
     return static_cast<form_width_t> (_m_width);
 }
 
+std::ostream &
+operator << (std::ostream &os, form const &obj)
+{
+  return os << pri::form (obj.name ());
+}
+
 namespace
 {
   dw_class_set
@@ -112,6 +119,12 @@ attribute::attribute (int a_name, dw_class_set const &a_classes)
   , _m_classes (include_indirect (a_classes))
 {}
 
+std::ostream &
+operator << (std::ostream &os, attribute const &obj)
+{
+  return os << pri::attr (obj.name ());
+}
+
 
 bool
 dwarf_version::form_allowed (int form) const
index 8108b42b23709c1c15162d743fdabf94ab0bab68..f3bee10b5e1879743adc448f1ec450cba5ae7270 100644 (file)
@@ -28,6 +28,7 @@
 #define DWARFLINT_DWARF_VERSION_HH
 
 #include <bitset>
+#include <iosfwd>
 #include "check_debug_info.ii"
 #include "dwarf_version.ii"
 
@@ -131,6 +132,8 @@ public:
     return _m_storclass;
   }
 };
+std::ostream &operator << (std::ostream &os, form const &obj);
+
 
 class attribute
 {
@@ -154,6 +157,7 @@ public:
     return _m_classes;
   }
 };
+std::ostream &operator << (std::ostream &os, attribute const &obj);
 
 class dwarf_version
 {
index 79b6014725a99bbed235e5d5edf5e1082c6a0aa6..fac9526d260f074a8074bd1a757c9cae22bf8e98 100644 (file)
@@ -34,19 +34,19 @@ extern "C"
 #include "../lib/system.h"
 }
 
-#define REALLOC(A, BUF)                                                \
-  do {                                                         \
-    typeof ((A)) _a = (A);                                     \
-    if (_a->size == _a->alloc)                                 \
-      {                                                                \
-       if (_a->alloc == 0)                                     \
-         _a->alloc = 8;                                        \
-       else                                                    \
-         _a->alloc *= 2;                                       \
-       _a->BUF = (typeof (_a->BUF))                            \
-         xrealloc (_a->BUF,                                    \
-                   sizeof (*_a->BUF) * _a->alloc);             \
-      }                                                                \
+#define REALLOC(A, BUF)                                        \
+  do {                                                 \
+    typeof ((A)) _a = (A);                             \
+    if (_a->size == _a->alloc)                         \
+      {                                                        \
+       if (_a->alloc == 0)                             \
+         _a->alloc = 8;                                \
+       else                                            \
+         _a->alloc *= 2;                               \
+       _a->BUF = (typeof (_a->BUF))                    \
+         xrealloc (_a->BUF,                            \
+                   sizeof (*_a->BUF) * _a->alloc);     \
+      }                                                        \
   } while (0)
 
 #define WIPE(OBJ) memset (&OBJ, 0, sizeof (OBJ))
@@ -58,5 +58,7 @@ bool necessary_alignment (uint64_t start, uint64_t length,
 bool supported_version (unsigned version,
                        size_t num_supported, struct where *where, ...);
 
+#define UNREACHABLE assert (!"unreachable")
+
 
 #endif//DWARFLINT_MISC_HH