]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Check optional/expected/required attributes
authorPetr Machata <pmachata@redhat.com>
Fri, 20 Feb 2009 14:31:21 +0000 (15:31 +0100)
committerPetr Machata <pmachata@redhat.com>
Fri, 20 Feb 2009 14:31:21 +0000 (15:31 +0100)
* The code currently iterates over tree of DIEs.  This will be necessary
  for checking parent vs. expected children, but for attributes, it's an
  overkill, and we should check abbreviation table instead.  Also, this
  way, we report each mistake in abbreviation table separately for each
  DIE that uses the erroneous entry.

* All attributes are marked optional.  In future, we need to go through
  the standard, or employ some other source of knowledge (hi, Roland!),
  and adjust the optionality level.

* Vast majority of entries are derived from the table in Appendix A of the
  standard.  Some were added to reflect what I found in several debuginfo
  test cases that I've tried to check.  These entries are marked with
  "XXX" comment to distinguish them from the rest.

src/dwarflint-hl.cc
src/dwarflint.c
src/dwarflint.h

index fb7ae9264ae26043cab0ac3e0421ec14ae96c201..c2474c8a4562dc19f294d6ef1cade3ad6974d987 100644 (file)
 #include <set>
 #include <algorithm>
 #include <cinttypes>
+#include <cstdarg>
+#include <cassert>
+#include <iterator>
 
 #include "dwarflint.h"
+#include "dwarfstrings.h"
 #include "c++/dwarf"
 #include "../libdw/libdwP.h"
 
@@ -41,10 +45,19 @@ namespace
 {
   message_category cat (message_category c1,
                        message_category c2,
-                       message_category c3)
+                       message_category c3 = mc_none)
   {
     return static_cast<message_category> (c1 | c2 | c3);
   }
+
+  template <class T>
+  std::string
+  to_string (T x)
+  {
+    std::ostringstream o;
+    o << x;
+    return o.str();
+  }
 }
 
 struct hl_ctx
@@ -69,6 +82,953 @@ hl_ctx_delete (hl_ctx *hlctx)
   delete hlctx;
 }
 
+class acceptable_form
+{
+  typedef std::set <int> form_set;
+  form_set m_forms;
+
+public:
+  acceptable_form () {}
+
+  acceptable_form (int f, ...)
+  {
+    va_list ap;
+    va_start (ap, f);
+    m_forms.insert (f);
+    while ((f = va_arg (ap, int)))
+      m_forms.insert (f);
+    va_end (ap);
+  }
+
+  acceptable_form operator+ (acceptable_form const &other) const
+  {
+    acceptable_form ret;
+    ret.m_forms.insert (m_forms.begin (), m_forms.end ());
+    ret.m_forms.insert (other.m_forms.begin (), other.m_forms.end ());
+    return ret;
+  }
+
+  virtual bool acceptable (int form) const
+  {
+    return m_forms.find (form) != m_forms.end ();
+  }
+};
+
+class acceptable_form_map
+{
+  typedef std::map <int, acceptable_form> acceptable_map;
+  acceptable_map m_map;
+
+public:
+  acceptable_form_map ()
+  {
+    acceptable_form form_c_address (DW_FORM_addr, 0);
+    acceptable_form form_c_block (DW_FORM_block1, DW_FORM_block2,
+                                 DW_FORM_block4, DW_FORM_block, 0);
+    acceptable_form form_c_constant (DW_FORM_data1, DW_FORM_data2,
+                                    DW_FORM_data4, DW_FORM_data8,
+                                    DW_FORM_sdata, DW_FORM_udata, 0);
+    acceptable_form form_c_flag (DW_FORM_flag, 0);
+    acceptable_form form_c_ptr (DW_FORM_data4, DW_FORM_data8, 0);
+    // ^^ lineptr, loclistptr, macptr, rangelistptr
+    acceptable_form form_c_reference (DW_FORM_ref1, DW_FORM_ref2,
+                                     DW_FORM_ref4, DW_FORM_ref8,
+                                     DW_FORM_ref_udata, DW_FORM_ref_addr, 0);
+    acceptable_form form_c_string (DW_FORM_strp, DW_FORM_string, 0);
+    acceptable_form form_c_bcr = form_c_block + form_c_constant + form_c_reference;
+
+    std::map <int, acceptable_form> acceptable_forms;
+    m_map[DW_AT_sibling] = form_c_reference;
+    m_map[DW_AT_location] = form_c_block + form_c_ptr;
+    m_map[DW_AT_name] = form_c_string;
+    m_map[DW_AT_ordering] = form_c_constant;
+    m_map[DW_AT_byte_size] = form_c_bcr;
+    m_map[DW_AT_bit_offset] = form_c_bcr;
+    m_map[DW_AT_bit_size] = form_c_bcr;
+    m_map[DW_AT_stmt_list] = form_c_ptr;
+    m_map[DW_AT_low_pc] = form_c_address;
+    m_map[DW_AT_high_pc] = form_c_address;
+    m_map[DW_AT_language] = form_c_constant;
+    m_map[DW_AT_discr] = form_c_reference;
+    m_map[DW_AT_discr_value] = form_c_constant;
+    m_map[DW_AT_visibility] = form_c_constant;
+    m_map[DW_AT_import] = form_c_reference;
+    m_map[DW_AT_string_length] = form_c_block + form_c_ptr;
+    m_map[DW_AT_common_reference] = form_c_reference;
+    m_map[DW_AT_comp_dir] = form_c_string;
+    m_map[DW_AT_const_value] = form_c_block + form_c_constant + form_c_string;
+    m_map[DW_AT_containing_type] = form_c_reference;
+    m_map[DW_AT_default_value] = form_c_reference;
+    m_map[DW_AT_inline] = form_c_constant;
+    m_map[DW_AT_is_optional] = form_c_flag;
+    m_map[DW_AT_lower_bound] = form_c_block + form_c_constant + form_c_reference;
+    m_map[DW_AT_producer] = form_c_string;
+    m_map[DW_AT_prototyped] = form_c_flag;
+    m_map[DW_AT_return_addr] = form_c_block + form_c_ptr;
+    m_map[DW_AT_start_scope] = form_c_constant;
+    m_map[DW_AT_bit_stride] = form_c_constant;
+    m_map[DW_AT_upper_bound] = form_c_bcr;
+    m_map[DW_AT_abstract_origin] = form_c_reference;
+    m_map[DW_AT_accessibility] = form_c_constant;
+    m_map[DW_AT_address_class] = form_c_constant;
+    m_map[DW_AT_artificial] = form_c_flag;
+    m_map[DW_AT_base_types] = form_c_reference;
+    m_map[DW_AT_calling_convention] = form_c_constant;
+    m_map[DW_AT_count] = form_c_bcr;
+    m_map[DW_AT_data_member_location] = form_c_block + form_c_constant + form_c_ptr;
+    m_map[DW_AT_decl_column] = form_c_constant;
+    m_map[DW_AT_decl_file] = form_c_constant;
+    m_map[DW_AT_decl_line] = form_c_constant;
+    m_map[DW_AT_declaration] = form_c_flag;
+    m_map[DW_AT_discr_list] = form_c_block;
+    m_map[DW_AT_encoding] = form_c_constant;
+    m_map[DW_AT_external] = form_c_flag;
+    m_map[DW_AT_frame_base] = form_c_block + form_c_ptr;
+    m_map[DW_AT_friend] = form_c_reference;
+    m_map[DW_AT_identifier_case] = form_c_constant;
+    m_map[DW_AT_macro_info] = form_c_ptr;
+    m_map[DW_AT_namelist_item] = form_c_block;
+    m_map[DW_AT_priority] = form_c_reference;
+    m_map[DW_AT_segment] = form_c_block + form_c_ptr;
+    m_map[DW_AT_specification] = form_c_reference;
+    m_map[DW_AT_static_link] = form_c_block + form_c_ptr;
+    m_map[DW_AT_type] = form_c_reference;
+    m_map[DW_AT_use_location] = form_c_block + form_c_ptr;
+    m_map[DW_AT_variable_parameter] = form_c_flag;
+    m_map[DW_AT_virtuality] = form_c_constant;
+    m_map[DW_AT_vtable_elem_location] = form_c_block + form_c_ptr;
+    m_map[DW_AT_allocated] = form_c_bcr;
+    m_map[DW_AT_associated] = form_c_bcr;
+    m_map[DW_AT_data_location] = form_c_block;
+    m_map[DW_AT_byte_stride] = form_c_bcr;
+    m_map[DW_AT_entry_pc] = form_c_address;
+    m_map[DW_AT_use_UTF8] = form_c_flag;
+    m_map[DW_AT_extension] = form_c_reference;
+    m_map[DW_AT_ranges] = form_c_ptr;
+    m_map[DW_AT_trampoline] = form_c_address + form_c_flag + form_c_reference + form_c_string;
+    m_map[DW_AT_call_column] = form_c_constant;
+    m_map[DW_AT_call_file] = form_c_constant;
+    m_map[DW_AT_call_line] = form_c_constant;
+    m_map[DW_AT_description] = form_c_string;
+    m_map[DW_AT_binary_scale] = form_c_constant;
+    m_map[DW_AT_decimal_scale] = form_c_constant;
+    m_map[DW_AT_small] = form_c_reference;
+    m_map[DW_AT_decimal_sign] = form_c_constant;
+    m_map[DW_AT_digit_count] = form_c_constant;
+    m_map[DW_AT_picture_string] = form_c_string;
+    m_map[DW_AT_mutable] = form_c_flag;
+    m_map[DW_AT_threads_scaled] = form_c_flag;
+    m_map[DW_AT_explicit] = form_c_flag;
+    m_map[DW_AT_object_pointer] = form_c_reference;
+    m_map[DW_AT_endianity] = form_c_constant;
+    m_map[DW_AT_elemental] = form_c_flag;
+    m_map[DW_AT_pure] = form_c_flag;
+    m_map[DW_AT_recursive] = form_c_flag;
+  }
+
+  bool acceptable (int attribute, int form) const
+  {
+    acceptable_map::const_iterator it = m_map.find (attribute);
+    if (it != m_map.end ())
+      throw std::runtime_error ("Unknown attribute #" + ::to_string (attribute));
+    else
+      return it->second.acceptable (form);
+  }
+};
+
+enum optionality
+{
+  opt_optional = 0,    // may or may not be present
+  opt_required,                // bogus if missing
+  opt_expected,                // suspicious if missing
+};
+
+struct expected_set
+{
+  typedef std::map <int, optionality> expectation_map;
+
+private:
+  expectation_map m_map;
+
+public:
+#define DEF_FILLER(WHAT)                                               \
+  expected_set &WHAT (int attribute)                                   \
+  {                                                                    \
+    assert (m_map.find (attribute) == m_map.end ());                   \
+    m_map.insert (std::make_pair (attribute, opt_##WHAT));             \
+    return *this;                                                      \
+  }                                                                    \
+  expected_set &WHAT (std::set <int> const &attributes)                        \
+  {                                                                    \
+    for (std::set <int>::const_iterator it = attributes.begin ();      \
+        it != attributes.end (); ++it)                                 \
+      WHAT (*it);                                                      \
+    return *this;                                                      \
+  }
+
+  DEF_FILLER (required)
+  DEF_FILLER (expected)
+  DEF_FILLER (optional)
+#undef DEF_FILLER
+
+  expectation_map const &map () const
+  {
+    return m_map;
+  }
+};
+
+class expected_map
+{
+  typedef std::map <int, expected_set> expected_map_t;
+
+protected:
+  expected_map_t m_map;
+  expected_map () {}
+
+public:
+  expected_set::expectation_map const &map (int tag) const
+  {
+    expected_map_t::const_iterator it = m_map.find (tag);
+    if (it == m_map.end ())
+      throw std::runtime_error ("Unknown tag #" + ::to_string (tag));
+    return it->second.map ();
+  }
+};
+
+struct expected_at_map
+  : public expected_map
+{
+  expected_at_map ()
+  {
+    std::set <int> at_set_decl;
+    at_set_decl.insert (DW_AT_decl_column);
+    at_set_decl.insert (DW_AT_decl_file);
+    at_set_decl.insert (DW_AT_decl_line);
+
+    m_map [DW_TAG_access_declaration]
+      .optional (at_set_decl)
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_description)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      ;
+
+    m_map[DW_TAG_array_type]
+      .optional (at_set_decl)
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_allocated)
+      .optional (DW_AT_associated)
+      .optional (DW_AT_bit_stride)
+      .optional (DW_AT_byte_size)
+      .optional (DW_AT_data_location)
+      .optional (DW_AT_declaration)
+      .optional (DW_AT_description)
+      .optional (DW_AT_name)
+      .optional (DW_AT_ordering)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_specification)
+      .optional (DW_AT_start_scope)
+      .optional (DW_AT_type)
+      .optional (DW_AT_visibility)
+      ;
+
+    m_map [DW_TAG_base_type]
+      .optional (DW_AT_allocated)
+      .optional (DW_AT_associated)
+      .optional (DW_AT_binary_scale)
+      .optional (DW_AT_bit_offset)
+      .optional (DW_AT_bit_size)
+      .optional (DW_AT_byte_size)
+      .optional (DW_AT_data_location)
+      .optional (DW_AT_decimal_scale)
+      .optional (DW_AT_decimal_sign)
+      .optional (DW_AT_description)
+      .optional (DW_AT_digit_count)
+      .optional (DW_AT_encoding)
+      .optional (DW_AT_endianity)
+      .optional (DW_AT_name)
+      .optional (DW_AT_picture_string)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_small)
+      ;
+
+    m_map [DW_TAG_catch_block]
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_high_pc)
+      .optional (DW_AT_low_pc)
+      .optional (DW_AT_ranges)
+      .optional (DW_AT_segment)
+      .optional (DW_AT_sibling)
+      ;
+
+    m_map [DW_TAG_class_type]
+      .optional (at_set_decl)
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_allocated)
+      .optional (DW_AT_associated)
+      .optional (DW_AT_byte_size)
+      .optional (DW_AT_data_location)
+      .optional (DW_AT_declaration)
+      .optional (DW_AT_description)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_specification)
+      .optional (DW_AT_start_scope)
+      .optional (DW_AT_visibility)
+      .optional (DW_AT_containing_type) // XXX added to reflect reality
+      ;
+
+    m_map [DW_TAG_common_block]
+      .optional (at_set_decl)
+      .optional (DW_AT_declaration)
+      .optional (DW_AT_description)
+      .optional (DW_AT_location)
+      .optional (DW_AT_name)
+      .optional (DW_AT_segment)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_visibility)
+      ;
+
+    m_map [DW_TAG_common_inclusion]
+      .optional (at_set_decl)
+      .optional (DW_AT_common_reference)
+      .optional (DW_AT_declaration)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_visibility)
+      ;
+
+    m_map [DW_TAG_compile_unit]
+      .optional (DW_AT_base_types)
+      .optional (DW_AT_comp_dir)
+      .optional (DW_AT_identifier_case)
+      .optional (DW_AT_high_pc)
+      .optional (DW_AT_language)
+      .optional (DW_AT_low_pc)
+      .optional (DW_AT_macro_info)
+      .optional (DW_AT_name)
+      .optional (DW_AT_producer)
+      .optional (DW_AT_ranges)
+      .optional (DW_AT_segment)
+      .optional (DW_AT_stmt_list)
+      .optional (DW_AT_use_UTF8)
+      .optional (DW_AT_entry_pc) // XXX added to reflect reality
+      ;
+
+    m_map [DW_TAG_condition]
+      .optional (at_set_decl)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      ;
+
+    m_map [DW_TAG_const_type]
+      .optional (DW_AT_allocated)
+      .optional (DW_AT_associated)
+      .optional (DW_AT_data_location)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_type)
+      ;
+
+    m_map [DW_TAG_constant]
+      .optional (at_set_decl)
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_const_value)
+      .optional (DW_AT_declaration)
+      .optional (DW_AT_description)
+      .optional (DW_AT_endianity)
+      .optional (DW_AT_external)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_start_scope)
+      .optional (DW_AT_type)
+      .optional (DW_AT_visibility)
+      ;
+
+    m_map [DW_TAG_dwarf_procedure]
+      .optional (DW_AT_location)
+      ;
+
+    m_map [DW_TAG_entry_point]
+      .optional (DW_AT_address_class)
+      .optional (DW_AT_description)
+      .optional (DW_AT_frame_base)
+      .optional (DW_AT_low_pc)
+      .optional (DW_AT_name)
+      .optional (DW_AT_return_addr)
+      .optional (DW_AT_segment)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_static_link)
+      .optional (DW_AT_type)
+      ;
+
+    m_map [DW_TAG_enumeration_type]
+      .optional (at_set_decl)
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_allocated)
+      .optional (DW_AT_associated)
+      .optional (DW_AT_bit_stride)
+      .optional (DW_AT_byte_size)
+      .optional (DW_AT_byte_stride)
+      .optional (DW_AT_data_location)
+      .optional (DW_AT_declaration)
+      .optional (DW_AT_description)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_specification)
+      .optional (DW_AT_start_scope)
+      .optional (DW_AT_type)
+      .optional (DW_AT_visibility)
+      ;
+
+    m_map [DW_TAG_enumerator]
+      .optional (at_set_decl)
+      .optional (DW_AT_const_value)
+      .optional (DW_AT_description)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      ;
+
+    m_map [DW_TAG_file_type]
+      .optional (at_set_decl)
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_allocated)
+      .optional (DW_AT_associated)
+      .optional (DW_AT_byte_size)
+      .optional (DW_AT_data_location)
+      .optional (DW_AT_description)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_start_scope)
+      .optional (DW_AT_type)
+      .optional (DW_AT_visibility)
+      ;
+
+    m_map [DW_TAG_formal_parameter]
+      .optional (at_set_decl)
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_artificial)
+      .optional (DW_AT_const_value)
+      .optional (DW_AT_default_value)
+      .optional (DW_AT_description)
+      .optional (DW_AT_endianity)
+      .optional (DW_AT_is_optional)
+      .optional (DW_AT_location)
+      .optional (DW_AT_name)
+      .optional (DW_AT_segment)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_type)
+      .optional (DW_AT_variable_parameter)
+      ;
+
+    m_map [DW_TAG_friend]
+      .optional (at_set_decl)
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_friend)
+      .optional (DW_AT_sibling)
+      ;
+
+    m_map [DW_TAG_imported_declaration]
+      .optional (at_set_decl)
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_description)
+      .optional (DW_AT_import)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_start_scope)
+      ;
+
+    m_map [DW_TAG_imported_module]
+      .optional (at_set_decl)
+      .optional (DW_AT_import)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_start_scope)
+      ;
+
+    m_map [DW_TAG_imported_unit]
+      .optional (DW_AT_import)
+      ;
+
+    m_map [DW_TAG_inheritance]
+      .optional (at_set_decl)
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_data_member_location)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_type)
+      .optional (DW_AT_virtuality)
+      ;
+
+    m_map [DW_TAG_inlined_subroutine]
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_call_column)
+      .optional (DW_AT_call_file)
+      .optional (DW_AT_call_line)
+      .optional (DW_AT_entry_pc)
+      .optional (DW_AT_high_pc)
+      .optional (DW_AT_low_pc)
+      .optional (DW_AT_ranges)
+      .optional (DW_AT_return_addr)
+      .optional (DW_AT_segment)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_start_scope)
+      .optional (DW_AT_trampoline)
+      ;
+
+    m_map [DW_TAG_interface_type]
+      .optional (at_set_decl)
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_description)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_start_scope)
+      ;
+
+    m_map [DW_TAG_label]
+      .optional (at_set_decl)
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_description)
+      .optional (DW_AT_low_pc)
+      .optional (DW_AT_name)
+      .optional (DW_AT_segment)
+      .optional (DW_AT_start_scope)
+      .optional (DW_AT_sibling)
+      ;
+
+    m_map [DW_TAG_lexical_block]
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_description)
+      .optional (DW_AT_high_pc)
+      .optional (DW_AT_low_pc)
+      .optional (DW_AT_name)
+      .optional (DW_AT_ranges)
+      .optional (DW_AT_segment)
+      .optional (DW_AT_sibling)
+      ;
+
+    m_map [DW_TAG_member]
+      .optional (at_set_decl)
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_bit_offset)
+      .optional (DW_AT_bit_size)
+      .optional (DW_AT_byte_size)
+      .optional (DW_AT_data_member_location)
+      .optional (DW_AT_declaration)
+      .optional (DW_AT_description)
+      .optional (DW_AT_mutable)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_type)
+      .optional (DW_AT_visibility)
+      ;
+
+    m_map [DW_TAG_module]
+      .optional (at_set_decl)
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_declaration)
+      .optional (DW_AT_description)
+      .optional (DW_AT_entry_pc)
+      .optional (DW_AT_high_pc)
+      .optional (DW_AT_low_pc)
+      .optional (DW_AT_name)
+      .optional (DW_AT_priority)
+      .optional (DW_AT_ranges)
+      .optional (DW_AT_segment)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_specification)
+      .optional (DW_AT_visibility)
+      ;
+
+    m_map [DW_TAG_namelist]
+      .optional (at_set_decl)
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_declaration)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_visibility)
+      ;
+
+    m_map [DW_TAG_namelist_item]
+      .optional (at_set_decl)
+      .optional (DW_AT_namelist_item)
+      .optional (DW_AT_sibling)
+      ;
+
+    m_map [DW_TAG_namespace]
+      .optional (at_set_decl)
+      .optional (DW_AT_description)
+      .optional (DW_AT_extension)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_start_scope)
+      ;
+
+    m_map [DW_TAG_packed_type]
+      .optional (DW_AT_allocated)
+      .optional (DW_AT_associated)
+      .optional (DW_AT_data_location)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_type)
+      ;
+
+    m_map [DW_TAG_partial_unit]
+      .optional (DW_AT_base_types)
+      .optional (DW_AT_comp_dir)
+      .optional (DW_AT_description)
+      .optional (DW_AT_identifier_case)
+      .optional (DW_AT_high_pc)
+      .optional (DW_AT_language)
+      .optional (DW_AT_low_pc)
+      .optional (DW_AT_macro_info)
+      .optional (DW_AT_name)
+      .optional (DW_AT_producer)
+      .optional (DW_AT_ranges)
+      .optional (DW_AT_segment)
+      .optional (DW_AT_stmt_list)
+      .optional (DW_AT_use_UTF8)
+      ;
+
+    m_map [DW_TAG_pointer_type]
+      .optional (DW_AT_address_class)
+      .optional (DW_AT_allocated)
+      .optional (DW_AT_associated)
+      .optional (DW_AT_data_location)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_specification)
+      .optional (DW_AT_type)
+      .optional (DW_AT_byte_size) // XXX added to reflect reality
+      ;
+
+    m_map [DW_TAG_ptr_to_member_type]
+      .optional (at_set_decl)
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_address_class)
+      .optional (DW_AT_allocated)
+      .optional (DW_AT_associated)
+      .optional (DW_AT_containing_type)
+      .optional (DW_AT_data_location)
+      .optional (DW_AT_declaration)
+      .optional (DW_AT_description)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_type)
+      .optional (DW_AT_use_location)
+      .optional (DW_AT_visibility)
+      ;
+
+    m_map [DW_TAG_reference_type]
+      .optional (DW_AT_address_class)
+      .optional (DW_AT_allocated)
+      .optional (DW_AT_associated)
+      .optional (DW_AT_data_location)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_type)
+      .optional (DW_AT_byte_size) // XXX added to reflect reality
+      ;
+
+    m_map [DW_TAG_restrict_type]
+      .optional (DW_AT_allocated)
+      .optional (DW_AT_associated)
+      .optional (DW_AT_data_location)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_type)
+      ;
+
+    m_map [DW_TAG_set_type]
+      .optional (at_set_decl)
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_allocated)
+      .optional (DW_AT_associated)
+      .optional (DW_AT_byte_size)
+      .optional (DW_AT_data_location)
+      .optional (DW_AT_declaration)
+      .optional (DW_AT_description)
+      .optional (DW_AT_name)
+      .optional (DW_AT_start_scope)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_type)
+      .optional (DW_AT_visibility)
+      ;
+
+    m_map [DW_TAG_shared_type]
+      .optional (at_set_decl)
+      .optional (DW_AT_count)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_type)
+      ;
+
+    m_map [DW_TAG_string_type]
+      .optional (at_set_decl)
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_allocated)
+      .optional (DW_AT_associated)
+      .optional (DW_AT_byte_size)
+      .optional (DW_AT_data_location)
+      .optional (DW_AT_declaration)
+      .optional (DW_AT_description)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_start_scope)
+      .optional (DW_AT_string_length)
+      .optional (DW_AT_visibility)
+      ;
+
+    m_map [DW_TAG_structure_type]
+      .optional (at_set_decl)
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_allocated)
+      .optional (DW_AT_associated)
+      .optional (DW_AT_byte_size)
+      .optional (DW_AT_data_location)
+      .optional (DW_AT_declaration)
+      .optional (DW_AT_description)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_specification)
+      .optional (DW_AT_start_scope)
+      .optional (DW_AT_visibility)
+      .optional (DW_AT_containing_type) // XXX added to reflect reality
+      ;
+
+    m_map [DW_TAG_subprogram]
+      .optional (at_set_decl)
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_address_class)
+      .optional (DW_AT_artificial)
+      .optional (DW_AT_calling_convention)
+      .optional (DW_AT_declaration)
+      .optional (DW_AT_description)
+      .optional (DW_AT_elemental)
+      .optional (DW_AT_entry_pc)
+      .optional (DW_AT_explicit)
+      .optional (DW_AT_external)
+      .optional (DW_AT_frame_base)
+      .optional (DW_AT_high_pc)
+      .optional (DW_AT_inline)
+      .optional (DW_AT_low_pc)
+      .optional (DW_AT_name)
+      .optional (DW_AT_object_pointer)
+      .optional (DW_AT_prototyped)
+      .optional (DW_AT_pure)
+      .optional (DW_AT_ranges)
+      .optional (DW_AT_recursive)
+      .optional (DW_AT_return_addr)
+      .optional (DW_AT_segment)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_specification)
+      .optional (DW_AT_start_scope)
+      .optional (DW_AT_static_link)
+      .optional (DW_AT_trampoline)
+      .optional (DW_AT_type)
+      .optional (DW_AT_visibility)
+      .optional (DW_AT_virtuality)
+      .optional (DW_AT_vtable_elem_location)
+      .optional (DW_AT_MIPS_linkage_name) // XXX added to reflect reality
+      .optional (DW_AT_containing_type) // XXX added to reflect reality
+      ;
+
+    m_map [DW_TAG_subrange_type]
+      .optional (at_set_decl)
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_allocated)
+      .optional (DW_AT_associated)
+      .optional (DW_AT_bit_stride)
+      .optional (DW_AT_byte_size)
+      .optional (DW_AT_byte_stride)
+      .optional (DW_AT_count)
+      .optional (DW_AT_data_location)
+      .optional (DW_AT_declaration)
+      .optional (DW_AT_description)
+      .optional (DW_AT_lower_bound)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_threads_scaled)
+      .optional (DW_AT_type)
+      .optional (DW_AT_upper_bound)
+      .optional (DW_AT_visibility)
+      ;
+
+    m_map [DW_TAG_subroutine_type]
+      .optional (at_set_decl)
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_address_class)
+      .optional (DW_AT_allocated)
+      .optional (DW_AT_associated)
+      .optional (DW_AT_data_location)
+      .optional (DW_AT_declaration)
+      .optional (DW_AT_description)
+      .optional (DW_AT_name)
+      .optional (DW_AT_prototyped)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_start_scope)
+      .optional (DW_AT_type)
+      .optional (DW_AT_visibility)
+      ;
+
+    m_map [DW_TAG_template_type_parameter]
+      .optional (at_set_decl)
+      .optional (DW_AT_description)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_type)
+      ;
+
+    m_map [DW_TAG_template_value_parameter ]
+      .optional (at_set_decl)
+      .optional (DW_AT_const_value)
+      .optional (DW_AT_description)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_type)
+      ;
+
+    m_map [DW_TAG_thrown_type]
+      .optional (at_set_decl)
+      .optional (DW_AT_allocated)
+      .optional (DW_AT_associated)
+      .optional (DW_AT_data_location)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_type)
+      ;
+
+    m_map [DW_TAG_try_block]
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_high_pc)
+      .optional (DW_AT_low_pc)
+      .optional (DW_AT_ranges)
+      .optional (DW_AT_segment)
+      .optional (DW_AT_sibling)
+      ;
+
+    m_map [DW_TAG_typedef]
+      .optional (at_set_decl)
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_allocated)
+      .optional (DW_AT_associated)
+      .optional (DW_AT_data_location)
+      .optional (DW_AT_declaration)
+      .optional (DW_AT_description)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_start_scope)
+      .optional (DW_AT_type)
+      .optional (DW_AT_visibility)
+      ;
+
+    m_map [DW_TAG_union_type]
+      .optional (at_set_decl)
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_allocated)
+      .optional (DW_AT_associated)
+      .optional (DW_AT_byte_size)
+      .optional (DW_AT_data_location)
+      .optional (DW_AT_declaration)
+      .optional (DW_AT_description)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_specification)
+      .optional (DW_AT_start_scope)
+      .optional (DW_AT_visibility)
+      ;
+
+    m_map [DW_TAG_unspecified_parameters]
+      .optional (at_set_decl)
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_artificial)
+      .optional (DW_AT_sibling)
+      ;
+
+    m_map [DW_TAG_unspecified_type]
+      .optional (at_set_decl)
+      .optional (DW_AT_description)
+      .optional (DW_AT_name)
+      ;
+
+    m_map [DW_TAG_variable]
+      .optional (at_set_decl)
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_const_value)
+      .optional (DW_AT_declaration)
+      .optional (DW_AT_description)
+      .optional (DW_AT_endianity)
+      .optional (DW_AT_external)
+      .optional (DW_AT_location)
+      .optional (DW_AT_name)
+      .optional (DW_AT_segment)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_specification)
+      .optional (DW_AT_start_scope)
+      .optional (DW_AT_type)
+      .optional (DW_AT_visibility)
+      .optional (DW_AT_MIPS_linkage_name) // XXX added to reflect reality
+      ;
+
+    m_map [DW_TAG_variant]
+      .optional (at_set_decl)
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_declaration)
+      .optional (DW_AT_discr_list)
+      .optional (DW_AT_discr_value)
+      .optional (DW_AT_sibling)
+      ;
+
+    m_map [DW_TAG_variant_part]
+      .optional (at_set_decl)
+      .optional (DW_AT_abstract_origin)
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_declaration)
+      .optional (DW_AT_discr)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_type)
+      ;
+
+    m_map [DW_TAG_volatile_type]
+      .optional (at_set_decl)
+      .optional (DW_AT_allocated)
+      .optional (DW_AT_associated)
+      .optional (DW_AT_data_location)
+      .optional (DW_AT_name)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_type)
+      ;
+
+    m_map [DW_TAG_with_stmt]
+      .optional (DW_AT_accessibility)
+      .optional (DW_AT_address_class)
+      .optional (DW_AT_declaration)
+      .optional (DW_AT_high_pc)
+      .optional (DW_AT_location)
+      .optional (DW_AT_low_pc)
+      .optional (DW_AT_ranges)
+      .optional (DW_AT_segment)
+      .optional (DW_AT_sibling)
+      .optional (DW_AT_type)
+      .optional (DW_AT_visibility)
+      ;
+  }
+};
+
+static const acceptable_form_map acceptable_form;
+static const expected_at_map expected_at;
+//static const expected_children_map expected_children;
+
 bool
 check_matching_ranges (hl_ctx *hlctx)
 {
@@ -120,3 +1080,86 @@ check_matching_ranges (hl_ctx *hlctx)
 
   return true;
 }
+
+struct extract_tag {
+  int operator () (elfutils::dwarf::attribute const &at) {
+    return at.first;
+  }
+};
+
+static void
+recursively_validate (elfutils::dwarf::compile_unit const &cu,
+                     elfutils::dwarf::debug_info_entry const &parent)
+{
+  struct where where = WHERE (sec_info, NULL);
+  where_reset_1 (&where, cu.offset ());
+  where_reset_2 (&where, parent.offset ());
+
+  int parent_tag = parent.tag ();
+
+  // Set of attributes of this DIE.
+  std::set <int> attributes;
+  std::transform (parent.attributes ().begin (),
+                 parent.attributes ().end (),
+                 std::inserter (attributes, attributes.end ()),
+                 extract_tag ());
+
+  // Attributes that we expect at this DIE.
+  expected_set::expectation_map const &expect
+    = expected_at.map (parent_tag);
+
+  // Check missing attributes.
+  for (expected_set::expectation_map::const_iterator jt
+        = expect.begin (); jt != expect.end (); ++jt)
+    {
+      std::set <int>::iterator kt = attributes.find (jt->first);
+      if (kt == attributes.end ())
+       switch (jt->second)
+         {
+         case opt_required:
+           wr_message (cat (mc_impact_4, mc_info), &where,
+                       ": %s lacks required attribute %s.\n",
+                       dwarf_tag_string (parent_tag),
+                       dwarf_attr_string (jt->first));
+           break;
+
+         case opt_expected:
+           wr_message (cat (mc_impact_2, mc_info), &where,
+                       ": %s should contain attribute %s.\n",
+                       dwarf_tag_string (parent_tag),
+                       dwarf_attr_string (jt->first));
+         case opt_optional:
+           break;
+         };
+    }
+
+  // Check unexpected attributes.
+  for (std::set <int>::iterator jt = attributes.begin ();
+       jt != attributes.end (); ++jt)
+    {
+      expected_set::expectation_map::const_iterator kt = expect.find (*jt);
+      if (kt == expect.end ())
+       wr_message (cat (mc_impact_3, mc_info), &where,
+                   ": %s has attribute %s, which is not expected.\n",
+                   dwarf_tag_string (parent_tag),
+                   dwarf_attr_string (*jt));
+    }
+
+  // Check children recursively.
+  class elfutils::dwarf::debug_info_entry::children const &children
+    = parent.children ();
+  for (elfutils::dwarf::debug_info_entry::children::const_iterator jt
+        = children.begin (); jt != children.end (); ++jt)
+    recursively_validate (cu, *jt);
+}
+
+bool
+check_expected_trees (hl_ctx *hlctx)
+{
+  class elfutils::dwarf::compile_units const &cus = hlctx->dw.compile_units ();
+  for (elfutils::dwarf::compile_units::const_iterator it = cus.begin ();
+       it != cus.end (); ++it)
+    recursively_validate (*it, *it);
+
+  return true;
+}
index be844c3bd4aa8c2afd0f0be3e2599d5cee423450..c77b036d21ef39acd145205028286a0231925513 100644 (file)
@@ -987,7 +987,11 @@ process_file (Dwarf *dwarf, const char *fname, bool only_one)
   if (abbrev_chain != NULL)
     {
       if (info_data.data != NULL)
-       cu_chain = check_debug_info_structural (&info_data, abbrev_chain, str_data.data);
+       {
+         cu_chain = check_debug_info_structural (&info_data, abbrev_chain, str_data.data);
+         if (cu_chain != NULL)
+           check_expected_trees (hlctx);
+       }
       else if (!tolerate_nodebug)
        /* Hard error, not a message.  We can't debug without this.  */
        wr_error (NULL, ".debug_info data not found.\n");
index e92d343cbdb3d090feb3851d7cf311462eff9fdb..e54d2cf67ebbfd93e5dd6c82f936aa66b486801e 100644 (file)
@@ -18,6 +18,7 @@ extern "C"
   extern struct hl_ctx *hl_ctx_new (Dwarf *dwarf);
   extern void hl_ctx_delete (struct hl_ctx *hlctx);
   extern bool check_matching_ranges (struct hl_ctx *hlctx);
+  extern bool check_expected_trees (struct hl_ctx *hlctx);
 
 
   /* Functions and data structures describing location in Dwarf.  */