#include <sstream>
#include <list>
#include <map>
+#include <set>
#include <stack>
#include <algorithm>
#include <functional>
static const char *known_attribute (int);
static const char *known_tag (int);
- static inline std::string attribute_name (int code)
- {
- return known_name<known_attribute> (code);
- }
static inline std::string tag_name (int code)
{
return known_name<known_tag> (code);
return attribute_name (code);
}
+ static inline std::string attribute_name (const unsigned int code)
+ {
+ return known_name<known_attribute> (code);
+ }
+
+
private:
// XXX make this an instance method to include irritant context
static void throw_libdw (void) // XXX raises (...)
class attribute;
class attr_value;
+ class location_attr;
+ class range_list;
class debug_info_entry
{
}
friend class dwarf;
+ friend class attr_value;
protected:
inline debug_info_entry ()
if ((*i).tag () == ::DW_TAG_imported_unit)
// We have an imported unit. Look at its referent.
_m_stack.push ((*i).attributes ().at (::DW_AT_import)
- .ref ().raw_children ().begin ());
+ .reference ().raw_children ().begin ());
else
// This is some other DIE. Iterate on it.
break;
}
};
+ class compile_unit : public debug_info_entry
+ {
+ public:
+ inline compile_unit (const debug_info_entry &die)
+ : debug_info_entry (die) {}
+
+ /*
+ containers/iterators:
+
+ lines
+ macros
+
+ abbrevs (punt)
+
+ */
+ };
+
+ // These are the kinds of values that attributes can have.
+ enum value_space
+ {
+ // These spaces refer purely to DWARF concepts.
+ VS_flag, // Boolean.
+ VS_dwarf_constant, // Known DW_X_* space of integer constants.
+ VS_discr_list, // Block as used for DW_AT_discr_list.
+ VS_reference, // Pointer to another DIE.
+ VS_unit_reference, // Pointer to another CU DIE.
+ VS_lineptr, // Pointer into .debug_line section.
+ VS_macptr, // Pointer into .debug_macinfo section.
+ VS_rangelistptr, // Pointer into .debug_ranges section.
+
+ // These spaces refer to textual details of the program source.
+ VS_identifier, // String, identifier in source language.
+ VS_string, // String, miscellaneous use.
+ VS_source_file, // Source file, string or index into file table.
+ VS_source_line, // Line number in source file.
+ VS_source_column, // Column number in source file.
+
+ // These spaces refer to target-format values in the debuggee.
+ VS_address, // Address constant.
+ VS_constant, // Other constant, integer or in target formats.
+ VS_location, // Location expression or location list.
+ };
+
+ /* A source file can be just a file name. When represented in the
+ .debug_line file table, it can also have a modtime and a file size.
+ If the modtime or size stored is zero, it doesn't count. */
+ class source_file
+ {
+ friend class attr_value;
+ private:
+ ::Dwarf_Attribute _m_attr;
+ inline ::Dwarf_Attribute *thisattr () const
+ {
+ return const_cast< ::Dwarf_Attribute *> (&_m_attr);
+ }
+
+ source_file (const Dwarf_Attribute &attr) : _m_attr (attr) {}
+
+ public:
+ std::string to_string () const;
+
+ const char *name () const;
+ ::Dwarf_Word mtime () const;
+ ::Dwarf_Word size () const;
+
+ template<typename other_file>
+ bool operator== (const other_file &other) const
+ {
+ if (mtime () != 0)
+ {
+ ::Dwarf_Word other_mtime = other.mtime ();
+ if (other_mtime != 0 && other_mtime != mtime ())
+ return false;
+ }
+ if (size () != 0)
+ {
+ ::Dwarf_Word other_size = other.size ();
+ if (other_size != 0 && other_size != size ())
+ return false;
+ }
+ return !strcmp (name (), other.name ());
+ }
+
+ template<typename other_file>
+ inline bool operator!= (const other_file &other) const
+ {
+ return !(*this == other);
+ }
+ };
+
// This describes the value of an attribute.
- // XXX dummy for now
class attr_value
{
+ friend class attribute;
+ friend class location_attr;
+ friend class range_list;
+ private:
+ const ::Dwarf_Attribute _m_attr;
+ inline ::Dwarf_Attribute *thisattr () const
+ {
+ return const_cast< ::Dwarf_Attribute *> (&_m_attr);
+ }
+
+ attr_value (const ::Dwarf_Attribute &attr) : _m_attr (attr) {}
+
public:
- attr_value () {}
- attr_value (const attr_value &v) {}
+ // not copyable, don't worry about ref lifetime(?)
+ // attr_value (const attr_value &v) : _m_attr (v.attr) {}
+
+ value_space what_space () const;
+
+ std::string to_string () const;
+
+ inline debug_info_entry reference () const
+ {
+ debug_info_entry result;
+ xif (::dwarf_formref_die (thisattr (), result.thisdie ()) == NULL);
+ return result;
+ }
+ inline compile_unit unit_reference () const
+ {
+ return reference ();
+ }
+
+ // XXX reloc, dwfl
+ ::Dwarf_Addr address () const;
+
+ bool flag () const;
+
+ const location_attr location () const;
+
+ const char *string () const;
+ inline const char *identifier () const
+ {
+ return string ();
+ }
+
+ const class source_file source_file () const;
+
+ // XXX reloc
+ ::Dwarf_Word constant () const;
+ ::Dwarf_Sword signed_constant () const;
+ // XXX better type??
+ std::string constant_block () const;
+
+ // XXX known enums
+ // dwarf_enum dwarf_constant () const;
+
+ inline const range_list ranges () const
+ {
+ return range_list (*this);
+ }
+
+ // XXX lineptr
+ // XXX macptr
- inline bool operator== (const attr_value &other) const
+ template<typename value>
+ inline bool operator== (const value &other) const
{
- return true; // XXX dummy value comparison always true
+ const value_space what = what_space ();
+ if (other.what_space () == what)
+ switch (what)
+ {
+ case VS_reference:
+ case VS_unit_reference:
+ // return reference () == other.reference ();
+ return true; // XXX temporary stub
+
+ case VS_flag:
+ return flag () == other.flag ();
+
+ case VS_rangelistptr:
+ return ranges () == other.ranges ();
+
+ case VS_lineptr: // XXX punt for now, treat as constant
+ case VS_macptr: // XXX punt for now, treat as constant
+ /*FALLTHRU*/
+ case VS_constant:
+ case VS_dwarf_constant:
+ case VS_source_line:
+ case VS_source_column:
+ return constant () == other.constant ();
+
+ case VS_identifier:
+ return !strcmp (identifier (), other.identifier ());
+
+ case VS_string:
+ return !strcmp (string (), other.string ());
+
+ case VS_address:
+ return address () == other.address ();
+
+ case VS_source_file:
+ return source_file () == other.source_file ();
+
+ case VS_location:
+ return location () == other; // XXX
+
+ case VS_discr_list:
+ throw std::runtime_error ("XXX unimplemented");
+ }
+ return false;
}
inline bool operator!= (const attr_value &other) const
{
return !(*this == other);
}
+ };
+
+ /* A location attribute yields a location expression.
+ Either it's a single expression, or a map of PC to location. */
+ class location_attr
+ {
+ friend class attr_value;
+ private:
+ const attr_value _m_attr;
+
+ location_attr (const attr_value &attr) : _m_attr (attr) {}
+
+ bool singleton () const; // XXX temp hack
+
+ public:
+ std::string to_string () const;
+
+ template<typename other_attr>
+ bool operator== (const other_attr &other) const
+ {
+ // XXX hack
+ if (singleton ())
+ return _m_attr.constant_block () == other.constant_block ();
+ // loclistptr XXX punt for now, treat as constant
+ return _m_attr.constant () == other.constant ();
+ }
+
+ template<typename other_file>
+ inline bool operator!= (const other_file &other) const
+ {
+ return !(*this == other);
+ }
+ };
+
+ /* The DW_AT_ranges attribute yields a range list.
+ This is equivalent to unordered_set<pair<Dwarf_Addr, Dwarf_Addr> >. */
+ class range_list
+ {
+ friend class attr_value;
+ private:
+ const attr_value _m_attr;
+
+ range_list (const attr_value &attr) : _m_attr (attr) {}
+
+ public:
+ typedef std::pair< ::Dwarf_Addr, ::Dwarf_Addr> key_type;
+ typedef key_type value_type;
+
+ range_list (const range_list &other) : _m_attr (other._m_attr) {}
+
+ std::string to_string () const;
+
+ class const_iterator
+ : public std::iterator<std::input_iterator_tag, value_type>
+ {
+ friend class range_list;
+ private:
+ ::Dwarf_Addr _m_base;
+ ::Dwarf_Addr _m_begin;
+ ::Dwarf_Addr _m_end;
+ ::Dwarf_CU *_m_cu;
+ ptrdiff_t _m_offset;
+
+ inline const_iterator () // end () value
+ : _m_base (-1), _m_begin (0), _m_end (0), _m_cu (NULL), _m_offset (1)
+ {}
+ const_iterator (Dwarf_Attribute *);
+
+ public:
+ inline const_iterator (const const_iterator &i)
+ : _m_base (i._m_base), _m_cu (i._m_cu), _m_offset (i._m_offset) {}
+
+ inline value_type operator* () const
+ {
+ return std::make_pair (_m_base + _m_begin, _m_base + _m_end);
+ }
+
+ inline const_iterator &operator= (const const_iterator &other)
+ {
+ _m_base = other._m_base;
+ _m_begin = other._m_begin;
+ _m_end = other._m_end;
+ _m_cu = other._m_cu;
+ _m_offset = other._m_offset;
+ return *this;
+ }
+
+ inline bool operator== (const const_iterator &other) const
+ {
+ return _m_offset == other._m_offset;
+ }
+ inline bool operator!= (const const_iterator &other) const
+ {
+ return !(*this == other);
+ }
+
+ const_iterator &operator++ (); // prefix
+ inline const_iterator operator++ (int) // postfix
+ {
+ const_iterator prev = *this;
+ ++*this;
+ return prev;
+ }
+ };
+
+ const_iterator begin () const
+ {
+ return const_iterator (_m_attr.thisattr ());
+ }
+ const_iterator end () const
+ {
+ return const_iterator ();
+ }
+
+ const_iterator find (const key_type &match)
+ {
+ return std::find (begin (), end (), match);
+ }
+
+ private:
+ struct entry_contains
+ : public std::binary_function<key_type, ::Dwarf_Addr, bool>
+ {
+ inline bool operator() (const key_type &range, const ::Dwarf_Addr addr)
+ const
+ {
+ return addr >= range.first && addr < range.second;
+ }
+ };
+
+ public:
+ const_iterator find (const ::Dwarf_Addr addr) const
+ {
+ return std::find_if (begin (), end (),
+ std::bind2nd (entry_contains (), addr));
+ }
+
+ inline operator std::set<key_type> () const
+ {
+ return std::set<key_type> (begin (), end ());
+ }
- debug_info_entry ref () const
+ template<typename ranges>
+ inline bool operator== (const ranges &other) const
{
- return debug_info_entry (); // XXX dummy hack
+ /* Our container is unordered (i.e., in file order). A range list
+ is conceptually equal if all the pairs match, regardless of the
+ order. But the std::equal algorithm will compare corresponding
+ elements in order. So we need an ordered set for comparison. */
+ const std::set<key_type> mine = *this;
+ const std::set<key_type> his = other;
+ return mine == his;
+ }
+ template<typename ranges>
+ inline bool operator!= (const ranges &other) const
+ {
+ return !(*this == other);
}
};
class attribute
{
friend class debug_info_entry::raw_attributes::const_iterator;
+ friend class attr_value;
private:
- const ::Dwarf_Attribute _m_attr;
inline ::Dwarf_Attribute *thisattr () const
{
- return const_cast< ::Dwarf_Attribute *> (&_m_attr);
+ return second.thisattr ();
}
class lhs
};
attribute (const ::Dwarf_Attribute &attr)
- : _m_attr (attr), first (*this) {}
+ : first (*this), second (attr) {}
public:
lhs first;
attr_value second;
inline attribute (const attribute &a)
- : _m_attr (a._m_attr), first (*this) {}
+ : first (*this), second (a.second) {}
// This lets pair<...> x = (attribute) y work.
template<typename value>
{
return !(*this == other);
}
- };
-
- class compile_unit : public debug_info_entry
- {
- public:
- inline compile_unit (const debug_info_entry &die)
- : debug_info_entry (die) {}
-
- /*
- containers/iterators:
-
- lines
- macros
-
- abbrevs (punt)
- */
+ inline std::string to_string () const
+ {
+ std::string result = attribute_name (::dwarf_whatattr (thisattr ()));
+ result += "=";
+ result += second.to_string ();
+ return result;
+ }
};
// Container for raw CUs in file order, intended to be compatible
--- /dev/null
+#include <config.h>
+#include "dwarf"
+
+using namespace std;
+using namespace elfutils;
+
+#define VS(what) (1U << dwarf::VS_##what)
+
+/* Return a bitmask of value spaces expected for this attribute of this tag.
+ Primarily culled from the DWARF 3 spec: 7.5.4, Figure 20. */
+
+static unsigned int
+expected_value_space (int attr, int tag)
+{
+
+ switch (attr)
+ {
+ case DW_AT_sibling:
+ case DW_AT_common_reference:
+ case DW_AT_containing_type:
+ case DW_AT_default_value:
+ case DW_AT_abstract_origin:
+ case DW_AT_base_types:
+ case DW_AT_friend:
+ case DW_AT_priority:
+ case DW_AT_specification:
+ case DW_AT_type:
+ case DW_AT_use_location:
+ case DW_AT_data_location:
+ case DW_AT_extension:
+ case DW_AT_small:
+ case DW_AT_object_pointer:
+ case DW_AT_namelist_item:
+ return VS(reference);
+
+ case DW_AT_location:
+ case DW_AT_string_length:
+ case DW_AT_return_addr:
+ case DW_AT_data_member_location:
+ case DW_AT_frame_base:
+ case DW_AT_segment:
+ case DW_AT_static_link:
+ case DW_AT_vtable_elem_location:
+ return VS(location);
+
+ case DW_AT_name:
+ switch (tag)
+ {
+ case DW_TAG_compile_unit:
+ case DW_TAG_partial_unit:
+ return VS(source_file);
+ default:
+ return VS(identifier);
+ }
+
+ case DW_AT_ordering:
+ case DW_AT_language:
+ case DW_AT_visibility:
+ case DW_AT_inline:
+ case DW_AT_accessibility:
+ case DW_AT_address_class:
+ case DW_AT_calling_convention:
+ case DW_AT_encoding:
+ case DW_AT_identifier_case:
+ case DW_AT_virtuality:
+ case DW_AT_endianity:
+ return VS(dwarf_constant);
+
+ case DW_AT_byte_size:
+ case DW_AT_byte_stride:
+ case DW_AT_bit_offset:
+ case DW_AT_bit_size:
+ case DW_AT_lower_bound:
+ case DW_AT_upper_bound:
+ case DW_AT_count:
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ return VS(reference) | VS(constant);
+
+ case DW_AT_stmt_list:
+ return VS(lineptr);
+ case DW_AT_macro_info:
+ return VS(macptr);
+ case DW_AT_ranges:
+ return VS(rangelistptr);
+
+ case DW_AT_low_pc:
+ case DW_AT_high_pc:
+ case DW_AT_entry_pc:
+ return VS(address);
+
+ case DW_AT_discr:
+ return VS(reference);
+ case DW_AT_discr_value:
+ return VS(constant);
+ case DW_AT_discr_list:
+ return VS(discr_list);
+
+ case DW_AT_import:
+ return VS(unit_reference);
+
+ case DW_AT_comp_dir:
+ return VS(source_file);
+
+ case DW_AT_const_value:
+ return VS(constant) | VS(string);
+
+ case DW_AT_is_optional:
+ case DW_AT_prototyped:
+ case DW_AT_artificial:
+ case DW_AT_declaration:
+ case DW_AT_external:
+ case DW_AT_variable_parameter:
+ case DW_AT_use_UTF8:
+ case DW_AT_mutable:
+ case DW_AT_threads_scaled:
+ case DW_AT_explicit:
+ case DW_AT_elemental:
+ case DW_AT_pure:
+ case DW_AT_recursive:
+ return VS(flag);
+
+ case DW_AT_producer:
+ return VS(string);
+
+ case DW_AT_start_scope:
+ return VS(constant);
+
+ case DW_AT_bit_stride:
+ case DW_AT_binary_scale:
+ case DW_AT_decimal_scale:
+ case DW_AT_decimal_sign:
+ case DW_AT_digit_count:
+ return VS(constant);
+
+ case DW_AT_decl_file:
+ case DW_AT_call_file:
+ return VS(source_file);
+ case DW_AT_decl_line:
+ case DW_AT_call_line:
+ return VS(source_line);
+ case DW_AT_decl_column:
+ case DW_AT_call_column:
+ return VS(source_column);
+
+ case DW_AT_trampoline:
+ return VS(address) | VS(flag) | VS(reference) | VS(string);
+
+ case DW_AT_description:
+ case DW_AT_picture_string:
+ return VS(string);
+
+ case DW_AT_MIPS_linkage_name:
+ return VS(identifier);
+ }
+
+ return 0;
+}
--- /dev/null
+#include <config.h>
+#include "dwarf"
+#include "known-dwarf.h"
+
+using namespace elfutils;
+using namespace std;
+
+
+const char *
+dwarf::known_tag (int tag)
+{
+ switch (tag)
+ {
+#define ONE_KNOWN_DW_TAG(name, id) case id: return #name;
+#define ONE_KNOWN_DW_TAG_DESC(name, id, desc) ONE_KNOWN_DW_TAG (name, id)
+ ALL_KNOWN_DW_TAG
+ }
+ return NULL;
+}
+
+const char *
+dwarf::known_attribute (int name)
+{
+ switch (name)
+ {
+#define ONE_KNOWN_DW_AT(name, id) case id: return #name;
+#define ONE_KNOWN_DW_AT_DESC(name, id, desc) ONE_KNOWN_DW_AT (name, id)
+ ALL_KNOWN_DW_AT
+ }
+ return NULL;
+}
--- /dev/null
+/* -*- C++ -*- interfaces for libdw.
+ 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"
+
+extern "C"
+{
+#include "libdwP.h"
+}
+
+using namespace elfutils;
+using namespace std;
+
+#include "dwarf-knowledge.cc"
+
+\f
+// dwarf::attr_value disambiguation and dispatch.
+
+/* For ambiguous the forms, we need to look up the expected
+ value spaces for this attribute to disambiguate.
+*/
+dwarf::value_space
+dwarf::attr_value::what_space () const
+{
+ unsigned int possible = 0;
+
+ switch (dwarf_whatform (thisattr ()))
+ {
+ case DW_FORM_flag:
+ return VS_flag;
+
+ case DW_FORM_addr:
+ return VS_address;
+
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ /* Location expression or target constant. */
+ possible = VS(location) | VS(constant);
+ break;
+
+ case DW_FORM_data1:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ case DW_FORM_udata:
+ case DW_FORM_sdata:
+ /* Target constant, known DWARF constant, or *ptr. */
+ possible = (VS(dwarf_constant) | VS(constant)
+ | VS(source_file) | VS(source_line) | VS(source_column)
+ | VS(location) // loclistptr
+ | VS(lineptr) | VS(macptr) | VS(rangelistptr));
+ break;
+
+ case DW_FORM_string:
+ case DW_FORM_strp:
+ /* Identifier, file name, or string. */
+ possible = VS(identifier) | VS(source_file) | VS(string);
+ break;
+
+ case DW_FORM_ref_addr:
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ possible = VS(unit_reference) | VS(reference);
+ break;
+
+ default:
+ throw std::runtime_error ("XXX bad form");
+ }
+
+ unsigned int expected = expected_value_space
+ (dwarf_whatattr (thisattr ()), 0); // XXX need tag!
+
+ if (unlikely ((expected & possible) == 0))
+ {
+ if (expected == 0 && possible == (VS(unit_reference) | VS(reference)))
+ // An unknown reference is a reference, not a unit_reference.
+ return VS_reference;
+
+ // Otherwise we don't know enough to treat it robustly.
+ throw std::runtime_error ("XXX ambiguous form in unexpected attribute");
+ }
+
+ const int first = ffs (expected & possible) - 1;
+ if (likely ((expected & possible) == (1U << first)))
+ return static_cast<value_space> (first);
+
+ throw std::runtime_error ("XXX ambiguous form");
+}
+
+static string
+hex_string (Dwarf_Word value)
+{
+ std::ostringstream os;
+ os.setf(std::ios::hex, std::ios::basefield);
+ os << value;
+ return os.str ();
+}
+
+static string
+dec_string (Dwarf_Word value)
+{
+ std::ostringstream os;
+ os << value;
+ return os.str ();
+}
+
+static string
+addr_string (Dwarf_Addr value)
+{
+ // XXX some hook for symbol resolver??
+ return hex_string (value);
+}
+
+static inline string
+plain_string (const char *filename)
+{
+ return string ("\"") + filename + "\"";
+}
+
+string
+dwarf::attr_value::to_string () const
+{
+ switch (what_space ())
+ {
+ case VS_flag:
+ return flag () ? "1" : "0";
+
+ case VS_rangelistptr:
+ return ranges ().to_string ();
+
+ 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_source_line:
+ case VS_source_column:
+ return dec_string (constant ());
+
+ case VS_identifier:
+ return plain_string (identifier ());
+
+ case VS_string:
+ return plain_string (string ());
+
+ case VS_address:
+ return addr_string (address ());
+
+ case VS_reference:
+ case VS_unit_reference:
+ return "XXX";
+
+ case VS_source_file:
+ return source_file ().to_string ();
+
+ case VS_location:
+ return location ().to_string ();
+
+ case VS_discr_list:
+ break; // XXX
+ }
+
+ throw std::runtime_error ("XXX unsupported value space");
+}
+
+// A few cases are trivial.
+#define SIMPLE(type, name, form) \
+ type \
+ dwarf::attr_value::name () const \
+ { \
+ type result; \
+ xif (dwarf_form##form (thisattr (), &result) < 0); \
+ return result; \
+ }
+
+SIMPLE (bool, flag, flag)
+
+// XXX check value_space is really constantish?? vs *ptr
+SIMPLE (Dwarf_Word, constant, udata)
+SIMPLE (Dwarf_Sword, signed_constant, sdata)
+
+SIMPLE (Dwarf_Addr, address, addr)
+
+const char *
+dwarf::attr_value::string () const
+{
+ const char *result = dwarf_formstring (thisattr ());
+ xif (result == NULL);
+ return result;
+}
+
+string
+dwarf::attr_value::constant_block () const
+{
+ Dwarf_Block block;
+
+ switch (dwarf_whatform (thisattr ()))
+ {
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ xif (dwarf_formblock (thisattr (), &block) < 0);
+ break;
+
+ case DW_FORM_data1:
+ block.length = 1;
+ block.data = thisattr ()->valp;
+ break;
+
+ case DW_FORM_data2:
+ block.length = 2;
+ block.data = thisattr ()->valp;
+ break;
+
+ case DW_FORM_data4:
+ block.length = 4;
+ block.data = thisattr ()->valp;
+ break;
+
+ case DW_FORM_data8:
+ block.length = 8;
+ block.data = thisattr ()->valp;
+ break;
+
+ case DW_FORM_udata:
+ case DW_FORM_sdata:
+ // XXX ?
+
+ default:
+ throw std::runtime_error ("XXX wrong form");
+ }
+
+ return std::string (reinterpret_cast<const char *> (block.data),
+ block.length);
+}
+\f
+// dwarf::source_file
+
+const class dwarf::source_file
+dwarf::attr_value::source_file () const
+{
+ switch (what_space ())
+ {
+ case VS_string:
+ case VS_source_file:
+ break;
+ default:
+ throw std::runtime_error ("XXX not a file name");
+ }
+ return source_file::source_file (_m_attr);
+}
+
+static bool
+stringform (Dwarf_Attribute *attr)
+{
+ switch (dwarf_whatform (attr))
+ {
+ case DW_FORM_string:
+ case DW_FORM_strp:
+ return true;
+ }
+ return false;
+}
+
+static bool
+get_files (Dwarf_Attribute *attr, Dwarf_Files **files, size_t *idx)
+{
+ Dwarf_Word result;
+ CUDIE (cudie, attr->cu);
+ if (dwarf_formudata (attr, &result) < 0
+ || dwarf_getsrcfiles (&cudie, files, NULL) < 0)
+ return true;
+ *idx = result;
+ return false;
+}
+
+Dwarf_Word
+dwarf::source_file::mtime () const
+{
+ if (stringform (thisattr ()))
+ return 0;
+
+ Dwarf_Files *files;
+ size_t idx;
+ xif (get_files (thisattr (), &files, &idx));
+
+ Dwarf_Word result;
+ xif (dwarf_filesrc (files, idx, &result, NULL) == NULL);
+ return result;
+}
+
+Dwarf_Word
+dwarf::source_file::size () const
+{
+ if (stringform (thisattr ()))
+ return 0;
+
+ Dwarf_Files *files;
+ size_t idx;
+ xif (get_files (thisattr (), &files, &idx));
+
+ Dwarf_Word result;
+ xif (dwarf_filesrc (files, idx, NULL, &result) == NULL);
+ return result;
+}
+
+const char *
+dwarf::source_file::name () const
+{
+ if (stringform (thisattr ()))
+ return dwarf_formstring (thisattr ());
+
+ Dwarf_Files *files;
+ size_t idx;
+ xif (get_files (thisattr (), &files, &idx));
+
+ const char *result = dwarf_filesrc (files, idx, NULL, NULL);
+ xif (result == NULL);
+ return result;
+}
+
+string
+dwarf::source_file::to_string () const
+{
+ if (stringform (thisattr ()))
+ return plain_string (dwarf_formstring (thisattr ()));
+
+ Dwarf_Files *files;
+ size_t idx;
+ xif (get_files (thisattr (), &files, &idx));
+
+ Dwarf_Word file_mtime;
+ Dwarf_Word file_size;
+ const char *result = dwarf_filesrc (files, idx, &file_mtime, &file_size);
+ xif (result == NULL);
+
+ if (likely (file_mtime == 0) && likely (file_size == 0))
+ return plain_string (result);
+
+ std::ostringstream os;
+ os << "{\"" << result << "," << file_mtime << "," << file_size << "}";
+ return os.str ();
+}
+\f
+// dwarf::location_attr
+
+const dwarf::location_attr
+dwarf::attr_value::location () const
+{
+ if (what_space () != VS_location)
+ throw std::runtime_error ("XXX not a location");
+
+ return location_attr (*this);
+}
+
+bool
+dwarf::location_attr::singleton () const
+{
+ switch (dwarf_whatform (_m_attr.thisattr ()))
+ {
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ return true;
+ }
+
+ return false;
+}
+
+string
+dwarf::location_attr::to_string () const
+{
+ if (singleton ())
+ return "XXX";
+ return hex_string (_m_attr.constant ());
+}
+\f
+// dwarf::range_list
+
+dwarf::range_list::const_iterator::const_iterator (Dwarf_Attribute *attr)
+ : _m_base (-1), _m_cu (attr->cu), _m_offset (0)
+{
+ ++*this;
+}
+
+dwarf::range_list::const_iterator &
+dwarf::range_list::const_iterator::operator++ ()
+{
+ const Elf_Data *d = _m_cu->dbg->sectiondata[IDX_debug_ranges];
+ if (unlikely (d == NULL))
+ throw std::runtime_error ("XXX no ranges");
+
+ if (unlikely (_m_offset < 0) || unlikely ((size_t) _m_offset >= d->d_size))
+ throw std::runtime_error ("XXX bad offset in ranges iterator");
+
+ unsigned char *readp = (reinterpret_cast<unsigned char *> (d->d_buf)
+ + _m_offset);
+
+ while (true)
+ {
+ if ((unsigned char *) d->d_buf + d->d_size - readp
+ < _m_cu->address_size * 2)
+ throw std::runtime_error ("XXX bad ranges");
+
+ if (_m_cu->address_size == 8)
+ {
+ _m_begin = read_8ubyte_unaligned_inc (_m_cu->dbg, readp);
+ _m_end = read_8ubyte_unaligned_inc (_m_cu->dbg, readp);
+ if (_m_begin == (uint64_t) -1l) /* Base address entry. */
+ {
+ _m_base = _m_end;
+ continue;
+ }
+ }
+ else
+ {
+ _m_begin = read_4ubyte_unaligned_inc (_m_cu->dbg, readp);
+ _m_end = read_4ubyte_unaligned_inc (_m_cu->dbg, readp);
+ if (_m_begin == (uint32_t) -1) /* Base address entry. */
+ {
+ _m_base = _m_end;
+ continue;
+ }
+ }
+
+ break;
+ }
+
+ if (_m_begin == 0 && _m_end == 0) /* End of list entry. */
+ _m_offset = 1;
+ else
+ {
+ _m_offset = readp - reinterpret_cast<unsigned char *> (d->d_buf);
+
+ if (_m_base == (Dwarf_Addr) -1)
+ {
+ CUDIE (cudie, _m_cu);
+
+ /* Find the base address of the compilation unit. It will
+ normally be specified by DW_AT_low_pc. In DWARF-3 draft 4,
+ the base address could be overridden by DW_AT_entry_pc. It's
+ been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
+ for compilation units with discontinuous ranges. */
+ Dwarf_Attribute attr_mem;
+ if (unlikely (dwarf_lowpc (&cudie, &_m_base) != 0)
+ && dwarf_formaddr (dwarf_attr (&cudie,
+ DW_AT_entry_pc,
+ &attr_mem),
+ &_m_base) != 0)
+ {
+ xif (true); // XXX
+ }
+ }
+ }
+
+ return *this;
+}
+
+string
+dwarf::range_list::to_string () const
+{
+ std::ostringstream os;
+ os.setf(std::ios::hex, std::ios::basefield);
+
+ os << "<";
+
+ bool first = true;
+ for (const_iterator i = begin (); i != end (); ++i)
+ {
+ value_type range = *i;
+ if (!first)
+ os << ",";
+ os << range.first << "-" << range.second;
+ first = false;
+ }
+
+ os << ">";
+
+ return os.str ();
+}
#define DIE_OFFSET_FROM_CU_OFFSET(cu_offset, offset_size) \
((cu_offset) + 3 * (offset_size) - 4 + 3)
-#define CUDIE(fromcu) \
- ((Dwarf_Die) \
- { \
- .cu = (fromcu), \
- .addr = ((char *) (fromcu)->dbg->sectiondata[IDX_debug_info]->d_buf \
- + (fromcu)->start + 3 * (fromcu)->offset_size - 4 + 3), \
+#define CUDIE_ADDR(fromcu) \
+ ((char *) (fromcu)->dbg->sectiondata[IDX_debug_info]->d_buf \
+ + DIE_OFFSET_FROM_CU_OFFSET ((fromcu)->start, (fromcu)->offset_size))
+
+#ifdef __cplusplus
+# define CUDIE(name, fromcu) \
+ Dwarf_Die name = { CUDIE_ADDR (fromcu), (fromcu), NULL, 0l }
+#else
+# define CUDIE(fromcu) \
+ ((Dwarf_Die) \
+ { \
+ .cu = (fromcu), \
+ .addr = CUDIE_ADDR (fromcu), \
})
-
+#endif
/* Macro information. */
struct Dwarf_Macro_s
libar_a_SOURCES = arlib.c arlib2.c
dwarfcmp_SOURCES = dwarfcmp.cc
+# XXX need to figure out C++ dso crapola
+dwarfcmp_SOURCES += ../libdw/c++/values.cc ../libdw/c++/known.cc
noinst_HEADERS = ld.h symbolhash.h sectionhash.h versionhash.h \
ldscript.h xelf.h unaligned.h
location () << "different attributes" << endl;
}
- void values (int name) const
+ void values (const string &a, const string &b) const
{
- location () << "different values for attribute 0x" << hex << name << endl;
+ location () << "attribute " << a << " vs " << b << endl;
}
};
{
result = a.second != b.second;
if (result != 0)
- say.values (a.first);
+ say.values (a.to_string (), b.to_string ());
}
return result;
}