]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Proper dwarf_constant attr value support with name fetchers.
authorRoland McGrath <roland@redhat.com>
Thu, 26 Mar 2009 04:22:46 +0000 (21:22 -0700)
committerRoland McGrath <roland@redhat.com>
Thu, 26 Mar 2009 04:22:46 +0000 (21:22 -0700)
libdw/ChangeLog
libdw/c++/dwarf
libdw/c++/dwarf_edit
libdw/c++/edit-values.cc
libdw/c++/known.cc
libdw/c++/values.cc
tests/run-dwarf-attributes.sh

index f2a73f2b52028587ef94ff202d0c37182125983d..f4e602e516a9e4f0637bc665d54ba9ed92f8ac20 100644 (file)
@@ -1,3 +1,10 @@
+2009-03-25  Roland McGrath  <roland@redhat.com>
+
+       * c++/dwarf, c++/values.cc: Proper dwarf_constant support.
+       * c++/dwarf_edit, c++/edit-values.cc: Likewise.
+       * c++/known.cc: New file.
+       * Makefile.am (libdwpp_a_SOURCES): Add it.
+
 2009-03-24  Petr Machata  <pmachata@redhat.com>
 
        * c++/dwarf (dwarf::debug_info_entry::raw_attributes):
index e32d34415c722c59f4a8deb3725b32e1ba822424..035248c061ccfda66228f4ed54b33ea364bd4cb4 100644 (file)
@@ -243,6 +243,24 @@ namespace elfutils
       return attributes::name (code);
     }
 
+    template<int key>
+    class known_enum
+    {
+    public:
+      static size_t prefix_length ();
+      static const char *identifier (int);
+      inline static const char *name (int value)
+      {
+       const char *id = identifier (value);
+       return id != NULL ? id + prefix_length () : NULL;
+      }
+
+      // XXX perhaps have iterator/lookup methods like a read-only map?
+    };
+
+    typedef known_enum< ::DW_AT_producer> forms;
+    typedef known_enum< ::DW_AT_location> ops;
+
   private:
     // XXX make this an instance method to include irritant context
     static void throw_libdw (void) // XXX raises (...)
@@ -361,6 +379,7 @@ namespace elfutils
     class file_table;
     class line_table;
     class line_entry;
+    class dwarf_enum;
 
     class debug_info_entry
     {
@@ -996,6 +1015,7 @@ namespace elfutils
       friend class attribute;
       friend class location_attr;
       friend class range_list;
+      friend class dwarf_enum;
     private:
       const int _m_tag;
       ::Dwarf_Attribute _m_attr;
@@ -1003,6 +1023,10 @@ namespace elfutils
       {
        return const_cast< ::Dwarf_Attribute *> (&_m_attr);
       }
+      inline int whatattr () const
+      {
+       return ::dwarf_whatattr (thisattr ());
+      }
 
       attr_value (int tag, const ::Dwarf_Attribute &attr)
        : _m_tag (tag), _m_attr (attr) {}
@@ -1058,9 +1082,12 @@ namespace elfutils
       ::Dwarf_Word constant () const;
       ::Dwarf_Sword signed_constant () const;
       const_vector<uint8_t> constant_block () const;
+      bool constant_is_integer () const;
 
-      // XXX known enums
-      // dwarf_enum dwarf_constant () const;
+      inline const dwarf_enum dwarf_constant () const
+      {
+       return dwarf_enum (*this);
+      }
 
       inline const range_list ranges () const
       {
@@ -1094,10 +1121,16 @@ namespace elfutils
 
            case VS_macptr:     // XXX punt for now, treat as constant
              /*FALLTHRU*/
-           case VS_constant:
            case VS_dwarf_constant:
              return constant () == other.constant ();
 
+           case VS_constant:
+             if (constant_is_integer ())
+               return (other.constant_is_integer ()
+                       && constant () == other.constant ());
+             return (!other.constant_is_integer ()
+                     && constant_block () == other.constant_block ());
+
            case VS_source_line:
              return source_line () == other.source_line ();
            case VS_source_column:
@@ -1703,6 +1736,26 @@ namespace elfutils
       }
     };
 
+    class dwarf_enum
+    {
+      friend class attr_value;
+    private:
+      const attr_value _m_attr;
+
+      dwarf_enum (const attr_value &attr) : _m_attr (attr) {}
+
+    public:
+      inline operator unsigned int () const
+      {
+       return _m_attr.constant ();
+      }
+
+      std::string to_string () const;
+
+      const char *identifier () const;
+      const char *name () const;
+    };
+
     // This describes one attribute, equivalent to pair<const int, attr_value>.
     class attribute
     {
index 1a8df1e8ae721fe95862acec5c683713720f002e..e2811bbd2f29e9b509677828cff2429d97bb38bd 100644 (file)
@@ -814,7 +814,10 @@ namespace elfutils
            _m_value = new value_address (other.address ());
            break;
          case dwarf::VS_constant:
-           _m_value = new value_constant (other.constant ());
+           if (other.constant_is_integer ())
+             _m_value = new value_constant (other.constant ());
+           else
+             _m_value = new value_constant_block (other.constant_block ());
            break;
          case dwarf::VS_source_line:
            _m_value = new value_source_line (other.source_line ());
@@ -826,7 +829,7 @@ namespace elfutils
            _m_value = new value_source_file (other.source_file ());
            break;
          case dwarf::VS_dwarf_constant:
-           _m_value = new value_dwarf_constant (other.constant ()); // XXX
+           _m_value = new value_dwarf_constant (other.dwarf_constant ());
            break;
          case dwarf::VS_reference:
            _m_value = new value_reference (other.reference ());
@@ -967,7 +970,15 @@ namespace elfutils
          (variant<value_constant_block> ());
       }
 
-      // dwarf_constant<>
+      inline ::Dwarf_Word &dwarf_constant () const
+      {
+       return variant<value_dwarf_constant> ().word;
+      }
+
+      inline bool constant_is_integer () const
+      {
+       return dynamic_cast<value_constant *> (_m_value) != NULL;
+      }
 
       inline range_list &ranges () const
       {
@@ -1003,7 +1014,11 @@ namespace elfutils
            case dwarf::VS_lineptr:
              return line_info () == other.line_info ();
            case dwarf::VS_constant:
-             return constant () == other.constant ();
+             if (constant_is_integer ())
+               return (other.constant_is_integer ()
+                       && constant () == other.constant ());
+             return (!other.constant_is_integer ()
+                     && constant_block () == other.constant_block ());
            case dwarf::VS_source_file:
              return source_file () == other.source_file ();
            case dwarf::VS_source_line:
index 85da4ca8ea20dc4bba5ef29de3b8d954f746b995..f502c66c05fa4d4f3b234f2318ae30a103332388 100644 (file)
@@ -84,7 +84,8 @@ dwarf_edit::attr_value::what_space () const
     return dwarf::VS_source_column;
   if (typeid (*_m_value) == typeid (value_address))
     return dwarf::VS_address;
-  if (typeid (*_m_value) == typeid (value_constant))
+  if (typeid (*_m_value) == typeid (value_constant)
+      || typeid (*_m_value) == typeid (value_constant_block))
     return dwarf::VS_constant;
   if (typeid (*_m_value) == typeid (value_location))
     return dwarf::VS_location;
index 04473ca5c729dce774b10e7bc862a8a088008b48..81e4417e3a8c04da855dfdd7ca47e6645f1cc3ed 100644 (file)
@@ -1,3 +1,52 @@
+/* Known named integer values in DWARF.
+   Copyright (C) 2009 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
 #include <config.h>
 #include "dwarf"
 #include "known-dwarf.h"
@@ -29,3 +78,120 @@ dwarf::known_attribute (int name)
     }
   return NULL;
 }
+
+namespace elfutils
+{
+  template<int key>
+  size_t
+  dwarf::known_enum<key>::prefix_length ()
+  {
+    return 0;
+  }
+
+  template<int key>
+  const char *
+  dwarf::known_enum<key>::identifier (int value)
+  {
+    return NULL;
+  }
+
+#define ALL_KNOWN_ENUM                         \
+  KNOWN_ENUM (accessibility, ACCESS)           \
+  KNOWN_ENUM (encoding, ATE)                   \
+  KNOWN_ENUM (calling_convention, CC)          \
+  KNOWN_ENUM (decimal_sign, DS)                        \
+  KNOWN_ENUM (endianity, END)                  \
+  KNOWN_ENUM (identifier_case, ID)             \
+  KNOWN_ENUM (inline, INL)                     \
+  KNOWN_ENUM (language, LANG)                  \
+  KNOWN_ENUM (ordering, ORD)                   \
+  KNOWN_ENUM (virtuality, VIRTUALITY)          \
+  KNOWN_ENUM (visibility, VIS)
+
+#define ONE_KNOWN_DW_ACCESS(name, id)          KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_ATE(name, id)             KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_CC(name, id)              KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_DS(name, id)              KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_END(name, id)             KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_ID(name, id)              KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_INL(name, id)             KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_LANG(name, id)            KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_LANG_DESC(name, id, desc) KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_ORD(name, id)             KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_INL(name, id)             KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_VIRTUALITY(name, id)      KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_VIS(name, id)             KNOWN_ENUM_CASE (id)
+
+  // Stupid C++ doesn't do [x] = y initializers.
+#define KNOWN_ENUM(attr, enum)                         \
+  template<>                                           \
+  size_t                                               \
+  dwarf::known_enum<DW_AT_##attr>::prefix_length ()    \
+  {                                                    \
+    return sizeof ("DW_" #enum "_") - 1;               \
+  }                                                    \
+  template<>                                           \
+  const char *                                         \
+  dwarf::known_enum<DW_AT_##attr>::identifier (int value)      \
+  {                                                    \
+    switch (value)                                     \
+      {                                                        \
+       ALL_KNOWN_DW_##enum                             \
+      }                                                        \
+    return NULL;                                       \
+  }
+#define KNOWN_ENUM_CASE(id)    case id: return #id;
+
+  ALL_KNOWN_ENUM
+
+  // Not really enum cases, but pretend they are.
+#define ONE_KNOWN_DW_FORM(name, id)            KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_OP(name, id)              KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_OP_DESC(name, id, desc)   KNOWN_ENUM_CASE (id)
+  KNOWN_ENUM (producer, FORM)
+  KNOWN_ENUM (location, OP)
+
+#undef KNOWN_ENUM
+#undef KNOWN_ENUM_CASE
+};
+
+const char *
+dwarf::dwarf_enum::identifier () const
+{
+  switch (_m_attr.whatattr ())
+    {
+# define KNOWN_ENUM(attr, enum)                                                \
+      case DW_AT_##attr:                                               \
+       return dwarf::known_enum<DW_AT_##attr>::identifier (*this);
+
+      ALL_KNOWN_ENUM
+
+# undef KNOWN_ENUM
+    }
+
+  return NULL;
+}
+
+const char *
+dwarf::dwarf_enum::name () const
+{
+  switch (_m_attr.whatattr ())
+    {
+# define KNOWN_ENUM(attr, enum)                                                \
+      case DW_AT_##attr:                                               \
+       return dwarf::known_enum<DW_AT_##attr>::name (*this);
+
+      ALL_KNOWN_ENUM
+
+# undef KNOWN_ENUM
+    }
+
+  return NULL;
+}
+
+std::string
+dwarf::dwarf_enum::to_string () const
+{
+  const char *known = name ();
+  return known == NULL ? subr::hex_string (*this) : std::string (known);
+}
index 0c31d5b3f3be37cec042eb7b8809e0a759c9502c..63686eea3efce734393d44137909e840c1c1932a 100644 (file)
@@ -184,9 +184,11 @@ dwarf::attr_value::to_string () const
     case VS_lineptr:   // XXX punt for now, treat as constant
     case VS_macptr:    // XXX punt for now, treat as constant
     case VS_constant:
-    case VS_dwarf_constant:
       return hex_string (constant ());
 
+    case VS_dwarf_constant:
+      return dwarf_constant ().to_string ();
+
     case VS_source_line:
     case VS_source_column:
       return dec_string (constant ());
@@ -243,6 +245,31 @@ dwarf::attr_value::string () const
   return result;
 }
 
+bool
+dwarf::attr_value::constant_is_integer () const
+{
+  switch (dwarf_whatform (thisattr ()))
+    {
+    case DW_FORM_block:
+    case DW_FORM_block1:
+    case DW_FORM_block2:
+    case DW_FORM_block4:
+      return false;
+
+    case DW_FORM_data1:
+    case DW_FORM_data2:
+    case DW_FORM_data4:
+    case DW_FORM_data8:
+    case DW_FORM_udata:
+    case DW_FORM_sdata:
+      return true;
+
+    default:
+      throw std::runtime_error ("XXX wrong form");
+    }
+}
+
+
 const_vector<uint8_t>
 dwarf::attr_value::constant_block () const
 {
index e39c42f7b2945eaa63cf575da682b3755663ad56..22c7289d9ce9ada1600f1bfac76acba772265334 100755 (executable)
@@ -1,7 +1,6 @@
 #! /bin/sh
-# Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005 Red Hat, Inc.
+# Copyright (C) 2009 Red Hat, Inc.
 # This file is part of Red Hat elfutils.
-# Written by Ulrich Drepper <drepper@redhat.com>, 1999.
 #
 # Red Hat elfutils is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by the
@@ -30,9 +29,9 @@ testfiles testfile
 
 testrun_compare ./dwarf-print --depth=1 testfile <<\EOF
 testfile:
- <compile_unit offset=[0xb] stmt_list=0 high_pc=0x804845a low_pc=0x804842c name="m.c" comp_dir="/home/drepper/gnu/new-bu/build/ttt" producer="GNU C 2.96 20000731 (Red Hat Linux 7.0)" language=0x1>...
- <compile_unit offset=[0xca] stmt_list=0x4b high_pc=0x8048466 low_pc=0x804845c name="b.c" comp_dir="/home/drepper/gnu/new-bu/build/ttt" producer="GNU C 2.96 20000731 (Red Hat Linux 7.0)" language=0x1>...
- <compile_unit offset=[0x15fc] stmt_list=0x1e0 high_pc=0x8048472 low_pc=0x8048468 name="f.c" comp_dir="/home/drepper/gnu/new-bu/build/ttt" producer="GNU C 2.96 20000731 (Red Hat Linux 7.0)" language=0x1>...
+ <compile_unit offset=[0xb] stmt_list=0 high_pc=0x804845a low_pc=0x804842c name="m.c" comp_dir="/home/drepper/gnu/new-bu/build/ttt" producer="GNU C 2.96 20000731 (Red Hat Linux 7.0)" language=C89>...
+ <compile_unit offset=[0xca] stmt_list=0x4b high_pc=0x8048466 low_pc=0x804845c name="b.c" comp_dir="/home/drepper/gnu/new-bu/build/ttt" producer="GNU C 2.96 20000731 (Red Hat Linux 7.0)" language=C89>...
+ <compile_unit offset=[0x15fc] stmt_list=0x1e0 high_pc=0x8048472 low_pc=0x8048468 name="f.c" comp_dir="/home/drepper/gnu/new-bu/build/ttt" producer="GNU C 2.96 20000731 (Red Hat Linux 7.0)" language=C89>...
 EOF
 
 exit 0