]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
dwarflint: Retrofit proper marking of exprloc and loclistptr to earlier DWARFs
authorPetr Machata <pmachata@redhat.com>
Fri, 8 Oct 2010 23:28:52 +0000 (01:28 +0200)
committerPetr Machata <pmachata@redhat.com>
Fri, 8 Oct 2010 23:28:52 +0000 (01:28 +0200)
- as a consequence, is_location_attrib is gone
- in check_debug_abbrev, we now check for appropriateness all form/attribute
  pairs, not just those that are location attribs
- too-wide references are now checked in one place for all reference types
- pointer checking now actually looks sane--the maze of DW_FORM_/DW_AT_
  switches was replaced by a straighforward switch on ver->form_class
- this introduces a testcase failure
- and similar work needs to be done for other cl_*ref classes

dwarflint/check_debug_abbrev.cc
dwarflint/check_debug_abbrev.hh
dwarflint/check_debug_info.cc
dwarflint/dwarf_2.cc
dwarflint/dwarf_3.cc
dwarflint/dwarf_4.cc
dwarflint/dwarf_version-imp.hh

index b010f23b72ca22fab75820933f8a44e50a69e2dc..bca382ad6f437dd00d9b4744e3720a4784950c56 100644 (file)
@@ -358,13 +358,16 @@ namespace
                                       "attribute form"))
              throw check_base::failed ();
 
+           /* Now if both are zero, this was the last attribute.  */
            null_attrib = attrib_name == 0 && attrib_form == 0;
 
-           /* Now if both are zero, this was the last attribute.  */
+           attribute const *attribute = NULL;
+           form const *form = NULL;
            if (!null_attrib)
              {
                /* Otherwise validate name and form.  */
-               if (attrib_name > DW_AT_hi_user)
+               attribute = ver->get_attribute (attrib_name);
+               if (attribute == NULL)
                  {
                    wr_error (where)
                      << "invalid name " << pri::hex (attrib_name)
@@ -373,7 +376,8 @@ namespace
                    continue;
                  }
 
-               if (!ver->form_allowed (attrib_form))
+               form = ver->get_form (attrib_form);
+               if (form == NULL)
                  {
                    wr_error (where)
                      << "invalid form " << pri::hex (attrib_form)
@@ -382,6 +386,10 @@ namespace
                    continue;
                  }
 
+               if (!ver->form_allowed (attribute->name (), form->name ()))
+                 complain_invalid_form (where, attrib_name, attrib_form,
+                                        "attribute");
+
                std::pair<std::map<unsigned, uint64_t>::iterator, bool> inserted
                  = seen.insert (std::make_pair (attrib_name, attr_off));
                if (!inserted.second)
@@ -433,14 +441,6 @@ namespace
                  };
              }
 
-           /* Similar for DW_AT_location and friends.  */
-           else if (is_location_attrib (attrib_name))
-             {
-               if (!ver->form_allowed (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)
@@ -528,18 +528,3 @@ check_debug_abbrev::~check_debug_abbrev ()
       free (it->second.abbr);
     }
 }
-
-bool
-is_location_attrib (uint64_t name)
-{
-  switch (name)
-    {
-    case DW_AT_location:
-    case DW_AT_frame_base:
-    case DW_AT_data_location:
-    case DW_AT_data_member_location:
-      return true;
-    default:
-      return false;
-    }
-}
index f905bd24f94a2db11149eeafdf9300fd8663b50a..9d1d77824f140c0400bf6084d60ef7583b619253 100644 (file)
@@ -86,8 +86,4 @@ public:
   ~check_debug_abbrev ();
 };
 
-// xxx When dwarf version objects are properly implemented, that's
-// where this should end up in.
-bool is_location_attrib (uint64_t name);
-
 #endif//DWARFLINT_CHECK_DEBUG_ABBREV_HH
index 406d0c887655d3d17353d900f7868a4872cfa8f4..6822d242ae3f5c76f2b2496eddc013b06261d4c8 100644 (file)
@@ -634,7 +634,9 @@ namespace
                form_name = value;
 
                // xxx Some of what's below is probably duplicated in
-               // check_debug_abbrev.  Consolidate.
+               // 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)
@@ -705,76 +707,66 @@ namespace
               relocation was made against.  */
            GElf_Sym **symbolp = NULL;
 
-           /* Setup locptr checking.  */
-           if (is_location_attrib (it->name))
+           assert (form);
+           assert (attribute);
+
+           dw_class cls = ver->form_class (form, attribute);
+           static dw_class_set ref_classes
+             (cl_reference, cl_loclistptr, cl_lineptr, cl_macptr,
+              cl_rangelistptr);
+
+           if (ref_classes.test (cls))
+             if (form->width (cu) == fw_8
+                 && cu->head->offset_size == 4)
+               wr_error (where)
+                 << "reference attribute with form \""
+                 << pri::form (form_name) << "\" in 32-bit CU."
+                 << std::endl;
+
+           /* Setup pointer checking.  */
+           switch (cls)
              {
-               if (form->width () == fw_8
-                   && cu->head->offset_size == 4)
-                 wr_error (where)
-                   << "location attribute with form \""
-                   << pri::form (form_name) << "\" in 32-bit CU."
-                   << std::endl;
+             case cl_loclistptr:
+               check_someptr = true;
+               value_check_cb = check_locptr;
+               extra_mc = mc_loc;
+               break;
 
-               if (ver->form_class (form, attribute) == cl_loclistptr)
-                 {
-                   value_check_cb = check_locptr;
-                   extra_mc = mc_loc;
-                   check_someptr = true;
-                 }
-             }
-           /* Setup rangeptr or lineptr checking.  */
-           else
-             switch (it->name)
-               {
-               case DW_AT_ranges:
-               case DW_AT_stmt_list:
-                 {
-                   switch (form_name)
-                     {
-                     case DW_FORM_data8:
-                       if (cu->head->offset_size == 4)
-                         // xxx could now also be checked during abbrev loading
-                         wr_error (where)
-                           << pri::attr (it->name)
-                           << " with form DW_FORM_data8 in 32-bit CU."
-                           << std::endl;
-                       /* fall-through */
-
-                     case DW_FORM_data4:
-                     case DW_FORM_sec_offset:
-                       check_someptr = true;
-                       if (it->name == DW_AT_ranges)
-                         {
-                           value_check_cb = check_rangeptr;
-                           extra_mc = mc_ranges;
-                         }
-                       else
-                         {
-                           assert (it->name == DW_AT_stmt_list);
-                           value_check_cb = check_lineptr;
-                           extra_mc = mc_line;
-                         }
-                       break;
-                     }
-                   break;
+             case cl_rangelistptr:
+               check_someptr = true;
+               value_check_cb = check_rangeptr;
+               extra_mc = mc_ranges;
+               break;
 
-                 case DW_AT_low_pc:
-                   relocatedp = &low_pc_relocated;
-                   symbolp = &low_pc_symbol;
-                   valuep = &low_pc;
-                   break;
+             case cl_lineptr:
+               check_someptr = true;
+               value_check_cb = check_lineptr;
+               extra_mc = mc_line;
+               break;
 
-                 case DW_AT_high_pc:
-                   relocatedp = &high_pc_relocated;
-                   symbolp = &high_pc_symbol;
-                   valuep = &high_pc;
-                   break;
+             default:
+               ;
+             };
 
-                 case DW_AT_decl_file:
-                   value_check_cb = check_decl_file;
-                   break;
-                 }
-               }
+           /* Setup low_pc / high_pc checking.  */
+           switch (it->name)
+             {
+             case DW_AT_low_pc:
+               relocatedp = &low_pc_relocated;
+               symbolp = &low_pc_symbol;
+               valuep = &low_pc;
+               break;
+
+             case DW_AT_high_pc:
+               relocatedp = &high_pc_relocated;
+               symbolp = &high_pc_symbol;
+               valuep = &high_pc;
+               break;
+
+             case DW_AT_decl_file:
+               value_check_cb = check_decl_file;
+               break;
+             }
 
            /* Setup per-form checking & relocation.  */
            switch (form_name)
@@ -860,7 +852,7 @@ namespace
                  break;
 
                // Read & validate the block body.
-               if (is_location_attrib (it->name))
+               if (cls == cl_exprloc)
                  {
                    uint64_t expr_start
                      = cu->head->offset + read_ctx_get_offset (ctx);
@@ -869,8 +861,6 @@ namespace
                      return -1;
                  }
                else
-                 /* xxx really skip_mismatched?  We just don't
-                    know how to process these...  */
                  relocation_skip (reloc,
                                   read_ctx_get_offset (ctx) + value,
                                   &where, skip_mismatched);
index 2a240e5991cb74ae3de95b6fedfd16e68964a35b..c227ebfec3ab43a6d2608a7172bad8a78b7f5083 100644 (file)
@@ -34,8 +34,18 @@ namespace
   {
     dwarf_2_attributes ()
     {
+      // Note about location descriptions in DWARF 2 (and 3).  In
+      // DWARF 2, location expressions can have classes of cl_constant
+      // or cl_block.  But we need to tell those block expressions
+      // from any old block attribute to validate the expression, and
+      // those constants from any old number to validate the
+      // reference.  So we retrofit all the DW_FORM_block* forms and
+      // appropriate attributes with cl_exprloc form DWARF 4 and
+      // cl_loclistptr (even though in DWARF 4 it's actually only
+      // DW_FORM_exprloc that has this class).
+
       add (ref_attribute (DW_AT_sibling));
-      add (const_or_block_attribute (DW_AT_location));
+      add (location_attribute (DW_AT_location));
       add (string_attribute (DW_AT_name));
       add (const_attribute (DW_AT_ordering));
       add (const_attribute (DW_AT_byte_size));
@@ -49,7 +59,7 @@ namespace
       add (const_attribute (DW_AT_discr_value));
       add (const_attribute (DW_AT_visibility));
       add (ref_attribute (DW_AT_import));
-      add (const_or_block_attribute (DW_AT_string_length));
+      add (location_attribute (DW_AT_string_length));
       add (ref_attribute (DW_AT_common_reference));
       add (string_attribute (DW_AT_comp_dir));
       add (attribute (DW_AT_const_value,
@@ -61,7 +71,7 @@ namespace
       add (const_or_ref_attribute (DW_AT_lower_bound));
       add (string_attribute (DW_AT_producer));
       add (flag_attribute (DW_AT_prototyped));
-      add (const_or_block_attribute (DW_AT_return_addr));
+      add (location_attribute (DW_AT_return_addr));
       add (const_attribute (DW_AT_start_scope));
       add (const_attribute (DW_AT_bit_stride));
       add (const_or_ref_attribute (DW_AT_upper_bound));
@@ -72,7 +82,7 @@ namespace
       add (ref_attribute (DW_AT_base_types));
       add (const_attribute (DW_AT_calling_convention));
       add (const_or_ref_attribute (DW_AT_count));
-      add (ref_or_block_attribute (DW_AT_data_member_location));
+      add (static_location_attribute (DW_AT_data_member_location));
       add (const_attribute (DW_AT_decl_column));
       add (const_attribute (DW_AT_decl_file));
       add (const_attribute (DW_AT_decl_line));
@@ -80,39 +90,55 @@ namespace
       add (block_attribute (DW_AT_discr_list));
       add (const_attribute (DW_AT_encoding));
       add (flag_attribute (DW_AT_external));
-      add (const_or_block_attribute (DW_AT_frame_base));
+      add (location_attribute (DW_AT_frame_base));
       add (ref_attribute (DW_AT_friend));
       add (const_attribute (DW_AT_identifier_case));
       add (const_attribute (DW_AT_macro_info));
       add (block_attribute (DW_AT_namelist_item));
       add (ref_attribute (DW_AT_priority));
-      add (const_or_block_attribute (DW_AT_segment));
+      add (location_attribute (DW_AT_segment));
       add (ref_attribute (DW_AT_specification));
-      add (const_or_block_attribute (DW_AT_static_link));
+      add (location_attribute (DW_AT_static_link));
       add (ref_attribute (DW_AT_type));
-      add (const_or_block_attribute (DW_AT_use_location));
+      add (location_attribute (DW_AT_use_location));
       add (flag_attribute (DW_AT_variable_parameter));
       add (const_attribute (DW_AT_virtuality));
-      add (ref_or_block_attribute (DW_AT_vtable_elem_location));
+      add (static_location_attribute (DW_AT_vtable_elem_location));
     }
   };
 
+  struct exprloc_form
+    : public preset_form<sc_block, cl_exprloc, cl_block>
+  {
+    exprloc_form (int a_name, form_width_t a_width)
+      : preset_form<sc_block, cl_exprloc, cl_block> (a_name, a_width)
+    {}
+  };
+
+  // xxx We still need to retrofit all the cl_*ptr to above list of
+  // attributes.  Except cl_loclistptr which is already done.
+  typedef preset_form<sc_value,
+                     cl_constant, cl_lineptr, cl_loclistptr,
+                     cl_macptr, cl_rangelistptr> dw2_data_form;
+
   struct dwarf_2_forms
     : public form_table
   {
     dwarf_2_forms ()
     {
-      add (block_form (DW_FORM_block, fw_uleb));
-      add (block_form (DW_FORM_block1, fw_1));
-      add (block_form (DW_FORM_block2, fw_2));
-      add (block_form (DW_FORM_block4, fw_4));
-
-      add (const_form (DW_FORM_data1, fw_1));
-      add (const_form (DW_FORM_data2, fw_2));
-      add (const_form (DW_FORM_data4, fw_4));
-      add (const_form (DW_FORM_data8, fw_8));
-      add (const_form (DW_FORM_sdata, fw_sleb));
-      add (const_form (DW_FORM_udata, fw_uleb));
+      add (exprloc_form (DW_FORM_block, fw_uleb));
+      add (exprloc_form (DW_FORM_block1, fw_1));
+      add (exprloc_form (DW_FORM_block2, fw_2));
+      add (exprloc_form (DW_FORM_block4, fw_4));
+
+      // These constant forms can in theory, in legal DWARF 2,
+      // represent various pointers.
+      add (dw2_data_form (DW_FORM_data1, fw_1));
+      add (dw2_data_form (DW_FORM_data2, fw_2));
+      add (dw2_data_form (DW_FORM_data4, fw_4));
+      add (dw2_data_form (DW_FORM_data8, fw_8));
+      add (dw2_data_form (DW_FORM_sdata, fw_sleb));
+      add (dw2_data_form (DW_FORM_udata, fw_uleb));
 
       add (flag_form (DW_FORM_flag, fw_1));
 
index 64713c5b84ef53c7f93d8e8153d3981c1ba2be76..0aaa0764bde4344ea0c49c701d4f23ee0597a6c5 100644 (file)
 
 namespace
 {
-  typedef preset_attribute<cl_block, cl_loclistptr> block_or_loc_attribute;
-  typedef preset_attribute<cl_block, cl_constant, cl_reference>
-  block_const_ref_attribute;
-
   struct dwarf_3_attributes
     : public attribute_table
   {
     dwarf_3_attributes ()
     {
-      add (block_or_loc_attribute (DW_AT_location));
-      add (block_const_ref_attribute (DW_AT_byte_size));
-      add (block_const_ref_attribute (DW_AT_bit_offset));
-      add (block_const_ref_attribute (DW_AT_bit_size));
+      add (location_attribute (DW_AT_location));
+      add (dynval_attribute (DW_AT_byte_size));
+      add (dynval_attribute (DW_AT_bit_offset));
+      add (dynval_attribute (DW_AT_bit_size));
       add (attribute (DW_AT_stmt_list, cl_lineptr));
-      add (block_or_loc_attribute (DW_AT_string_length));
-      add (attribute (DW_AT_const_value,
-                     dw_class_set (cl_block, cl_constant, cl_string)));
-      add (block_const_ref_attribute (DW_AT_lower_bound));
-      add (block_or_loc_attribute (DW_AT_return_addr));
-      add (const_attribute (DW_AT_bit_stride));
-      add (block_const_ref_attribute (DW_AT_upper_bound));
-      add (block_const_ref_attribute (DW_AT_count));
+      add (location_attribute (DW_AT_string_length));
+      add (dynval_attribute (DW_AT_lower_bound));
+      add (location_attribute (DW_AT_return_addr));
+
+      // Note, DWARF 3 claims only a const class for DW_AT_bit_stride,
+      // but from 2.19 it's clear that this is an omission.
+      add (dynval_attribute (DW_AT_bit_stride));
+
+      add (dynval_attribute (DW_AT_upper_bound));
+      add (dynval_attribute (DW_AT_count));
       add (attribute (DW_AT_data_member_location,
-                     dw_class_set (cl_block, cl_constant, cl_loclistptr)));
-      add (block_or_loc_attribute (DW_AT_frame_base));
+                     dw_class_set (cl_exprloc, cl_constant, cl_loclistptr)));
+      add (location_attribute (DW_AT_frame_base));
       add (attribute (DW_AT_macro_info, cl_macptr));
-      add (block_or_loc_attribute (DW_AT_segment));
-      add (block_or_loc_attribute (DW_AT_static_link));
-      add (block_or_loc_attribute (DW_AT_use_location));
-      add (block_or_loc_attribute (DW_AT_vtable_elem_location));
-      add (block_const_ref_attribute (DW_AT_associated));
-      add (block_attribute (DW_AT_data_location));
-      add (block_const_ref_attribute (DW_AT_byte_stride));
+      add (location_attribute (DW_AT_segment));
+      add (location_attribute (DW_AT_static_link));
+      add (location_attribute (DW_AT_use_location));
+      add (location_attribute (DW_AT_vtable_elem_location));
+      add (dynval_attribute (DW_AT_allocated));
+      add (dynval_attribute (DW_AT_associated));
+      add (attribute (DW_AT_data_location, cl_exprloc));
+      add (dynval_attribute (DW_AT_byte_stride));
       add (addr_attribute (DW_AT_entry_pc));
       add (flag_attribute (DW_AT_use_UTF8));
       add (ref_attribute (DW_AT_extension));
@@ -95,15 +94,24 @@ namespace
   typedef preset_form<sc_value,
                      cl_constant, cl_lineptr, cl_loclistptr,
                      cl_macptr, cl_rangelistptr> dw3_data_form;
+  typedef preset_form<sc_block, cl_block, cl_exprloc> locexpr_form;
 
   struct dwarf_3_forms
     : public form_table
   {
     dwarf_3_forms ()
     {
+      add (offset_form (DW_FORM_ref_addr, cl_reference));
+
+      // In DWARF 2 we made all the const forms into various cl_*ptr,
+      // since that's how the standard was worded: it allowed
+      // DW_AT_location to have any constant form.  Revert that.
+      add (const_form (DW_FORM_data1, fw_1));
+      add (const_form (DW_FORM_data2, fw_2));
       add (dw3_data_form (DW_FORM_data4, fw_4));
       add (dw3_data_form (DW_FORM_data8, fw_8));
-      add (offset_form (DW_FORM_ref_addr, cl_reference));
+      add (const_form (DW_FORM_sdata, fw_sleb));
+      add (const_form (DW_FORM_udata, fw_uleb));
     }
   };
 
index 9b2f53d9e675bf67b901983de01dddd166708231..3894c4999a119c8b05aed62746df2e72dde56a77 100644 (file)
 
 namespace
 {
-  typedef preset_attribute<cl_exprloc, cl_loclistptr> exprloc_loclist_attribute;
-  typedef preset_attribute<cl_constant, cl_exprloc, cl_reference>
-  const_exprloc_ref_attribute;
-
   struct dwarf_4_attributes
     : public attribute_table
   {
     dwarf_4_attributes ()
     {
-      add (exprloc_loclist_attribute (DW_AT_location));
-      add (const_exprloc_ref_attribute (DW_AT_bit_offset));
-      add (const_exprloc_ref_attribute (DW_AT_bit_size));
-      add (attribute (DW_AT_high_pc,
-                     dw_class_set (cl_address, cl_constant)));
-      add (exprloc_loclist_attribute (DW_AT_string_length));
-      add (attribute (DW_AT_const_value,
-                     dw_class_set (cl_block, cl_constant, cl_string)));
-      add (const_exprloc_ref_attribute (DW_AT_lower_bound));
-      add (exprloc_loclist_attribute (DW_AT_return_addr));
-      add (const_exprloc_ref_attribute (DW_AT_bit_stride));
-      add (const_exprloc_ref_attribute (DW_AT_upper_bound));
-      add (const_exprloc_ref_attribute (DW_AT_count));
-      add (attribute (DW_AT_data_member_location,
-                     dw_class_set (cl_constant, cl_exprloc, cl_loclistptr)));
-      add (exprloc_loclist_attribute (DW_AT_frame_base));
+      add (attribute (DW_AT_high_pc, dw_class_set (cl_address, cl_constant)));
       add (ref_attribute (DW_AT_namelist_item));
-      add (exprloc_loclist_attribute (DW_AT_segment));
-      add (exprloc_loclist_attribute (DW_AT_static_link));
-      add (exprloc_loclist_attribute (DW_AT_use_location));
-      add (exprloc_loclist_attribute (DW_AT_vtable_elem_location));
-      add (const_exprloc_ref_attribute (DW_AT_allocated));
-      add (const_exprloc_ref_attribute (DW_AT_associated));
-      add (attribute (DW_AT_data_location, cl_exprloc));
-      add (const_exprloc_ref_attribute (DW_AT_byte_stride));
       add (ref_attribute (DW_AT_signature));
       add (flag_attribute (DW_AT_main_subprogram));
       add (const_attribute (DW_AT_data_bit_offset));
       add (flag_attribute (DW_AT_const_expr));
+      add (flag_attribute (DW_AT_enum_class));
+      add (string_attribute (DW_AT_linkage_name));
     }
   };
 
@@ -92,6 +67,14 @@ namespace
       add (exprloc_form (DW_FORM_exprloc));
       add (flag_form (DW_FORM_flag_present, fw_0));
       add (ref_form (DW_FORM_ref_sig8, fw_8));
+
+      // In DWARF 2 we claim that blocks are exprloc forms (see
+      // comment there).  Revert back to pure blocks now that we have
+      // proper support for cl_exprloc.
+      add (block_form (DW_FORM_block, fw_uleb));
+      add (block_form (DW_FORM_block1, fw_1));
+      add (block_form (DW_FORM_block2, fw_2));
+      add (block_form (DW_FORM_block4, fw_4));
     }
   };
 
index 70ad40279bc78958e363b802dbcb56984ba588d8..19a63ca1f11c5a169644ab8dd4e164823822b4db 100644 (file)
@@ -86,6 +86,7 @@ typedef preset_form<sc_block, cl_block> block_form;
 typedef preset_form<sc_value, cl_constant> const_form;
 typedef preset_form<sc_value, cl_reference> ref_form;
 typedef preset_form<sc_value, cl_flag> flag_form;
+typedef preset_form<sc_block, cl_block> block_form;
 
 typedef preset_attribute<cl_constant> const_attribute;
 typedef preset_attribute<cl_reference> ref_attribute;
@@ -93,10 +94,18 @@ typedef preset_attribute<cl_address> addr_attribute;
 typedef preset_attribute<cl_string> string_attribute;
 typedef preset_attribute<cl_flag> flag_attribute;
 typedef preset_attribute<cl_block> block_attribute;
-typedef preset_attribute<cl_block, cl_constant> const_or_block_attribute;
-typedef preset_attribute<cl_block, cl_reference> ref_or_block_attribute;
 typedef preset_attribute<cl_reference, cl_constant> const_or_ref_attribute;
 
+// [DWARF 3, DWARF 4, section 2.19]: attributes that [...] specify a
+// property [...] that is an integer value, where the value may be
+// known during compilation or may be computed dynamically during
+// execution.
+typedef preset_attribute<cl_constant, cl_exprloc,
+                        cl_reference> dynval_attribute;
+
+typedef preset_attribute<cl_exprloc, cl_loclistptr> location_attribute;
+typedef preset_attribute<cl_exprloc, cl_reference> static_location_attribute;
+
 class std_dwarf
   : public dwarf_version
 {