From da94ff4bb672e06e5ed1761f3ab5235dd8a5835e Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Wed, 25 Mar 2009 21:22:46 -0700 Subject: [PATCH] Proper dwarf_constant attr value support with name fetchers. --- libdw/ChangeLog | 7 ++ libdw/c++/dwarf | 59 +++++++++++- libdw/c++/dwarf_edit | 23 ++++- libdw/c++/edit-values.cc | 3 +- libdw/c++/known.cc | 166 ++++++++++++++++++++++++++++++++++ libdw/c++/values.cc | 29 +++++- tests/run-dwarf-attributes.sh | 9 +- 7 files changed, 282 insertions(+), 14 deletions(-) diff --git a/libdw/ChangeLog b/libdw/ChangeLog index f2a73f2b5..f4e602e51 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,10 @@ +2009-03-25 Roland McGrath + + * 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 * c++/dwarf (dwarf::debug_info_entry::raw_attributes): diff --git a/libdw/c++/dwarf b/libdw/c++/dwarf index e32d34415..035248c06 100644 --- a/libdw/c++/dwarf +++ b/libdw/c++/dwarf @@ -243,6 +243,24 @@ namespace elfutils return attributes::name (code); } + template + 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 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. class attribute { diff --git a/libdw/c++/dwarf_edit b/libdw/c++/dwarf_edit index 1a8df1e8a..e2811bbd2 100644 --- a/libdw/c++/dwarf_edit +++ b/libdw/c++/dwarf_edit @@ -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 ()); } - // dwarf_constant<> + inline ::Dwarf_Word &dwarf_constant () const + { + return variant ().word; + } + + inline bool constant_is_integer () const + { + return dynamic_cast (_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: diff --git a/libdw/c++/edit-values.cc b/libdw/c++/edit-values.cc index 85da4ca8e..f502c66c0 100644 --- a/libdw/c++/edit-values.cc +++ b/libdw/c++/edit-values.cc @@ -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; diff --git a/libdw/c++/known.cc b/libdw/c++/known.cc index 04473ca5c..81e4417e3 100644 --- a/libdw/c++/known.cc +++ b/libdw/c++/known.cc @@ -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 + . */ + #include #include "dwarf" #include "known-dwarf.h" @@ -29,3 +78,120 @@ dwarf::known_attribute (int name) } return NULL; } + +namespace elfutils +{ + template + size_t + dwarf::known_enum::prefix_length () + { + return 0; + } + + template + const char * + dwarf::known_enum::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::prefix_length () \ + { \ + return sizeof ("DW_" #enum "_") - 1; \ + } \ + template<> \ + const char * \ + dwarf::known_enum::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::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::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); +} diff --git a/libdw/c++/values.cc b/libdw/c++/values.cc index 0c31d5b3f..63686eea3 100644 --- a/libdw/c++/values.cc +++ b/libdw/c++/values.cc @@ -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 dwarf::attr_value::constant_block () const { diff --git a/tests/run-dwarf-attributes.sh b/tests/run-dwarf-attributes.sh index e39c42f7b..22c7289d9 100755 --- a/tests/run-dwarf-attributes.sh +++ b/tests/run-dwarf-attributes.sh @@ -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 , 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: - ... - ... - ... + ... + ... + ... EOF exit 0 -- 2.47.2