From: Roland McGrath Date: Mon, 26 Jan 2009 10:45:41 +0000 (-0800) Subject: Start at attr value interfaces, unfinished. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=724a8f0fc775e0193350de3d5fe3ff53d0bfb676;p=thirdparty%2Felfutils.git Start at attr value interfaces, unfinished. --- diff --git a/libdw/c++/dwarf b/libdw/c++/dwarf index 1f5dcd9f9..b64d3fb56 100644 --- a/libdw/c++/dwarf +++ b/libdw/c++/dwarf @@ -60,6 +60,7 @@ #include #include #include +#include #include #include #include @@ -167,10 +168,6 @@ namespace elfutils static const char *known_attribute (int); static const char *known_tag (int); - static inline std::string attribute_name (int code) - { - return known_name (code); - } static inline std::string tag_name (int code) { return known_name (code); @@ -183,6 +180,12 @@ namespace elfutils return attribute_name (code); } + static inline std::string attribute_name (const unsigned int code) + { + return known_name (code); + } + + private: // XXX make this an instance method to include irritant context static void throw_libdw (void) // XXX raises (...) @@ -293,6 +296,8 @@ namespace elfutils class attribute; class attr_value; + class location_attr; + class range_list; class debug_info_entry { @@ -304,6 +309,7 @@ namespace elfutils } friend class dwarf; + friend class attr_value; protected: inline debug_info_entry () @@ -617,7 +623,7 @@ namespace elfutils 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; @@ -779,26 +785,370 @@ namespace elfutils } }; + 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 + 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 + 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 + 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 + 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 + 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 >. */ + 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 + { + 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 + { + 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 () const + { + return std::set (begin (), end ()); + } - debug_info_entry ref () const + template + 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 mine = *this; + const std::set his = other; + return mine == his; + } + template + inline bool operator!= (const ranges &other) const + { + return !(*this == other); } }; @@ -806,11 +1156,11 @@ namespace elfutils 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 @@ -829,14 +1179,14 @@ namespace elfutils }; 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 @@ -855,23 +1205,14 @@ namespace elfutils { 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 diff --git a/libdw/c++/dwarf-knowledge.cc b/libdw/c++/dwarf-knowledge.cc new file mode 100644 index 000000000..b7827a457 --- /dev/null +++ b/libdw/c++/dwarf-knowledge.cc @@ -0,0 +1,158 @@ +#include +#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; +} diff --git a/libdw/c++/known.cc b/libdw/c++/known.cc new file mode 100644 index 000000000..18ca6297c --- /dev/null +++ b/libdw/c++/known.cc @@ -0,0 +1,31 @@ +#include +#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; +} diff --git a/libdw/c++/values.cc b/libdw/c++/values.cc new file mode 100644 index 000000000..0879f5894 --- /dev/null +++ b/libdw/c++/values.cc @@ -0,0 +1,535 @@ +/* -*- 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 + . */ + +#include +#include "dwarf" + +extern "C" +{ +#include "libdwP.h" +} + +using namespace elfutils; +using namespace std; + +#include "dwarf-knowledge.cc" + + +// 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 (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 (block.data), + block.length); +} + +// 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 (); +} + +// 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 ()); +} + +// 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 (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 (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 (); +} diff --git a/libdw/libdwP.h b/libdw/libdwP.h index 867ad89b4..4ccae9e9c 100644 --- a/libdw/libdwP.h +++ b/libdw/libdwP.h @@ -299,14 +299,21 @@ struct Dwarf_CU #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 diff --git a/src/Makefile.am b/src/Makefile.am index 96c9f9ada..be8989e36 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -82,6 +82,8 @@ ld_SOURCES = ld.c ldgeneric.c ldlex.l ldscript.y symbolhash.c sectionhash.c \ 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 diff --git a/src/dwarfcmp.cc b/src/dwarfcmp.cc index c4205828a..1bf342a90 100644 --- a/src/dwarfcmp.cc +++ b/src/dwarfcmp.cc @@ -164,9 +164,9 @@ struct context 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; } }; @@ -249,7 +249,7 @@ describe_mismatch (const dwarf::attribute &a, const dwarf::attribute &b, { result = a.second != b.second; if (result != 0) - say.values (a.first); + say.values (a.to_string (), b.to_string ()); } return result; }