[csw-devel] SF.net SVN: gar:[21254] csw/mgar/pkg/lang-python/pyelftools/trunk
chninkel at users.sourceforge.net
chninkel at users.sourceforge.net
Mon Jun 3 18:07:10 CEST 2013
Revision: 21254
http://gar.svn.sourceforge.net/gar/?rev=21254&view=rev
Author: chninkel
Date: 2013-06-03 16:07:09 +0000 (Mon, 03 Jun 2013)
Log Message:
-----------
lang-python/pyelftools/trunk: updated to last upstream code + symbol versioning support
Modified Paths:
--------------
csw/mgar/pkg/lang-python/pyelftools/trunk/Makefile
Added Paths:
-----------
csw/mgar/pkg/lang-python/pyelftools/trunk/files/0001-syminfo+symbol_versioning_support.patch
Modified: csw/mgar/pkg/lang-python/pyelftools/trunk/Makefile
===================================================================
--- csw/mgar/pkg/lang-python/pyelftools/trunk/Makefile 2013-06-03 16:04:14 UTC (rev 21253)
+++ csw/mgar/pkg/lang-python/pyelftools/trunk/Makefile 2013-06-03 16:07:09 UTC (rev 21254)
@@ -17,6 +17,8 @@
PACKAGING_PLATFORMS = solaris9-sparc solaris9-i386
PACKAGING_PLATFORMS += solaris10-sparc solaris10-i386
+PATCHFILES += 0001-syminfo+symbol_versioning_support.patch
+
TEST_SCRIPTS =
ARCHALL_CSWpy-pyelftools = 1
Added: csw/mgar/pkg/lang-python/pyelftools/trunk/files/0001-syminfo+symbol_versioning_support.patch
===================================================================
--- csw/mgar/pkg/lang-python/pyelftools/trunk/files/0001-syminfo+symbol_versioning_support.patch (rev 0)
+++ csw/mgar/pkg/lang-python/pyelftools/trunk/files/0001-syminfo+symbol_versioning_support.patch 2013-06-03 16:07:09 UTC (rev 21254)
@@ -0,0 +1,2070 @@
+diff -r 249a5ca85159 CHANGES
+--- a/CHANGES Wed Apr 17 05:57:58 2013 -0700
++++ b/CHANGES Mon Jun 03 17:52:42 2013 +0200
+@@ -1,7 +1,14 @@
+ Changelog
+ =========
+
+-+ Version 0.22 (17.04.2013)
+++ Version 0.22 (??)
++
++ - Added some initial support for parsing Solaris OpenCSW ELF files
++ (contributed by Yann Rouillard).
++ - Added some initial support for DWARF4 (as generated by gcc 4.8)
++ and DWARF generated by recent versions of Clang (3.3).
++
+++ Version 0.21 (17.04.2013)
+
+ - Added new example: dwarf_decode_address - decode function name and
+ file & line information from an address.
+diff -r 249a5ca85159 elftools/dwarf/callframe.py
+--- a/elftools/dwarf/callframe.py Wed Apr 17 05:57:58 2013 -0700
++++ b/elftools/dwarf/callframe.py Mon Jun 03 17:52:42 2013 +0200
+@@ -26,13 +26,13 @@
+ Eventually, each entry gets its own structs based on the initial
+ length field it starts with. The address_size, however, is taken
+ from base_structs. This appears to be a limitation of the DWARFv3
+- standard, fixed in v4 (where an address_size field exists for each
+- CFI. A discussion I had on dwarf-discuss confirms this.
+- Currently for base_structs I simply use the elfclass of the
+- containing file, but more sophisticated methods are used by
+- libdwarf and others, such as guessing which CU contains which FDEs
+- (based on their address ranges) and taking the address_size from
+- those CUs.
++ standard, fixed in v4.
++ A discussion I had on dwarf-discuss confirms this.
++ So for DWARFv4 we'll take the address size from the CIE header,
++ but for earlier versions will use the elfclass of the containing
++ file; more sophisticated methods are used by libdwarf and others,
++ such as guessing which CU contains which FDEs (based on their
++ address ranges) and taking the address_size from those CUs.
+ """
+ def __init__(self, stream, size, base_structs):
+ self.stream = stream
+@@ -99,6 +99,14 @@
+ header = struct_parse(
+ header_struct, self.stream, offset)
+
++ # If this is DWARF version 4 or later, we can have a more precise
++ # address size, read from the CIE header.
++ if entry_structs.dwarf_version >= 4:
++ entry_structs = DWARFStructs(
++ little_endian=entry_structs.little_endian,
++ dwarf_format=entry_structs.dwarf_format,
++ address_size=header.address_size)
++
+ # For convenience, compute the end offset for this entry
+ end_offset = (
+ offset + header.length +
+diff -r 249a5ca85159 elftools/dwarf/descriptions.py
+--- a/elftools/dwarf/descriptions.py Wed Apr 17 05:57:58 2013 -0700
++++ b/elftools/dwarf/descriptions.py Mon Jun 03 17:52:42 2013 +0200
+@@ -197,6 +197,12 @@
+ """
+ return '1' if attr.value else '0'
+
++def _describe_attr_present(attr, die, section_offset):
++ """ Some forms may simply mean that an attribute is present,
++ without providing any value.
++ """
++ return '1'
++
+ def _describe_attr_block(attr, die, section_offset):
+ s = '%s byte block: ' % len(attr.value)
+ s += ' '.join('%x' % item for item in attr.value) + ' '
+@@ -227,6 +233,9 @@
+ DW_FORM_block2=_describe_attr_block,
+ DW_FORM_block4=_describe_attr_block,
+ DW_FORM_block=_describe_attr_block,
++ DW_FORM_flag_present=_describe_attr_present,
++ DW_FORM_exprloc=_describe_attr_block,
++ DW_FORM_ref_sig8=_describe_attr_ref,
+ )
+
+
+diff -r 249a5ca85159 elftools/dwarf/dwarfinfo.py
+--- a/elftools/dwarf/dwarfinfo.py Wed Apr 17 05:57:58 2013 -0700
++++ b/elftools/dwarf/dwarfinfo.py Mon Jun 03 17:52:42 2013 +0200
+@@ -21,7 +21,7 @@
+
+
+ # Describes a debug section
+-#
++#
+ # stream: a stream object containing the data of this section
+ # name: section name in the container file
+ # global_offset: the global offset of the section in its container file
+@@ -30,7 +30,7 @@
+ # 'name' and 'global_offset' are for descriptional purposes only and
+ # aren't strictly required for the DWARF parsing to work.
+ #
+-DebugSectionDescriptor = namedtuple('DebugSectionDescriptor',
++DebugSectionDescriptor = namedtuple('DebugSectionDescriptor',
+ 'stream name global_offset size')
+
+
+@@ -51,7 +51,7 @@
+
+
+ class DWARFInfo(object):
+- """ Acts also as a "context" to other major objects, bridging between
++ """ Acts also as a "context" to other major objects, bridging between
+ various parts of the debug infromation.
+ """
+ def __init__(self,
+@@ -59,6 +59,7 @@
+ debug_info_sec,
+ debug_abbrev_sec,
+ debug_frame_sec,
++ eh_frame_sec,
+ debug_str_sec,
+ debug_loc_sec,
+ debug_ranges_sec,
+@@ -68,19 +69,20 @@
+
+ debug_*_sec:
+ DebugSectionDescriptor for a section. Pass None for sections
+- that don't exist. These arguments are best given with
++ that don't exist. These arguments are best given with
+ keyword syntax.
+ """
+ self.config = config
+ self.debug_info_sec = debug_info_sec
+ self.debug_abbrev_sec = debug_abbrev_sec
+ self.debug_frame_sec = debug_frame_sec
++ self.eh_frame_sec = eh_frame_sec
+ self.debug_str_sec = debug_str_sec
+ self.debug_loc_sec = debug_loc_sec
+ self.debug_ranges_sec = debug_ranges_sec
+ self.debug_line_sec = debug_line_sec
+
+- # This is the DWARFStructs the context uses, so it doesn't depend on
++ # This is the DWARFStructs the context uses, so it doesn't depend on
+ # DWARF format and address_size (these are determined per CU) - set them
+ # to default values.
+ self.structs = DWARFStructs(
+@@ -119,7 +121,7 @@
+ return self._abbrevtable_cache[offset]
+
+ def get_string_from_table(self, offset):
+- """ Obtain a string from the string table section, given an offset
++ """ Obtain a string from the string table section, given an offset
+ relative to the section.
+ """
+ return parse_cstring_from_stream(self.debug_str_sec.stream, offset)
+@@ -139,12 +141,12 @@
+ return None
+
+ def has_CFI(self):
+- """ Does this dwarf info has a CFI section?
++ """ Does this dwarf info have a dwarf_frame CFI section?
+ """
+ return self.debug_frame_sec is not None
+
+ def CFI_entries(self):
+- """ Get a list of CFI entries from the .debug_frame section.
++ """ Get a list of dwarf_frame CFI entries from the .debug_frame section.
+ """
+ cfi = CallFrameInfo(
+ stream=self.debug_frame_sec.stream,
+@@ -152,6 +154,20 @@
+ base_structs=self.structs)
+ return cfi.get_entries()
+
++ def has_EH_CFI(self):
++ """ Does this dwarf info have a eh_frame CFI section?
++ """
++ return self.eh_frame_sec is not None
++
++ def EH_CFI_entries(self):
++ """ Get a list of eh_frame CFI entries from the .eh_frame section.
++ """
++ cfi = CallFrameInfo(
++ stream=self.eh_frame_sec.stream,
++ size=self.eh_frame_sec.size,
++ base_structs=self.structs)
++ return cfi.get_entries()
++
+ def location_lists(self):
+ """ Get a LocationLists object representing the .debug_loc section of
+ the DWARF data, or None if this section doesn't exist.
+@@ -175,18 +191,18 @@
+ # Compute the offset of the next CU in the section. The unit_length
+ # field of the CU header contains its size not including the length
+ # field itself.
+- offset = ( offset +
+- cu['unit_length'] +
++ offset = ( offset +
++ cu['unit_length'] +
+ cu.structs.initial_length_field_size())
+ yield cu
+-
++
+ def _parse_CU_at_offset(self, offset):
+ """ Parse and return a CU at the given offset in the debug_info stream.
+ """
+ # Section 7.4 (32-bit and 64-bit DWARF Formats) of the DWARF spec v3
+- # states that the first 32-bit word of the CU header determines
++ # states that the first 32-bit word of the CU header determines
+ # whether the CU is represented with 32-bit or 64-bit DWARF format.
+- #
++ #
+ # So we peek at the first word in the CU header to determine its
+ # dwarf format. Based on it, we then create a new DWARFStructs
+ # instance suitable for this CU and use it to parse the rest.
+@@ -205,15 +221,15 @@
+ little_endian=self.config.little_endian,
+ dwarf_format=dwarf_format,
+ address_size=4)
+-
++
+ cu_header = struct_parse(
+ cu_structs.Dwarf_CU_header, self.debug_info_sec.stream, offset)
+ if cu_header['address_size'] == 8:
+ cu_structs = DWARFStructs(
+ little_endian=self.config.little_endian,
+ dwarf_format=dwarf_format,
+- address_size=8)
+-
++ address_size=8)
++
+ cu_die_offset = self.debug_info_sec.stream.tell()
+ dwarf_assert(
+ self._is_supported_version(cu_header['version']),
+@@ -224,11 +240,11 @@
+ structs=cu_structs,
+ cu_offset=offset,
+ cu_die_offset=cu_die_offset)
+-
++
+ def _is_supported_version(self, version):
+ """ DWARF version supported by this parser
+ """
+- return 2 <= version <= 3
++ return 2 <= version <= 4
+
+ def _parse_line_program_at_offset(self, debug_line_offset, structs):
+ """ Given an offset to the .debug_line section, parse the line program
+diff -r 249a5ca85159 elftools/dwarf/enums.py
+--- a/elftools/dwarf/enums.py Wed Apr 17 05:57:58 2013 -0700
++++ b/elftools/dwarf/enums.py Mon Jun 03 17:52:42 2013 +0200
+@@ -185,7 +185,9 @@
+ DW_AT_main_subprogram = 0x6a,
+ DW_AT_data_bit_offset = 0x6b,
+ DW_AT_const_expr = 0x6c,
+-
++ DW_AT_enum_class = 0x6d,
++ DW_AT_linkage_name = 0x6e,
++
+ DW_AT_MIPS_fde = 0x2001,
+ DW_AT_MIPS_loop_begin = 0x2002,
+ DW_AT_MIPS_tail_loop_begin = 0x2003,
+@@ -197,8 +199,46 @@
+ DW_AT_MIPS_abstract_name = 0x2009,
+ DW_AT_MIPS_clone_origin = 0x200a,
+ DW_AT_MIPS_has_inlines = 0x200b,
++ DW_AT_MIPS_stride_byte = 0x200c,
++ DW_AT_MIPS_stride_elem = 0x200d,
++ DW_AT_MIPS_ptr_dopetype = 0x200e,
++ DW_AT_MIPS_allocatable_dopetype = 0x200f,
++ DW_AT_MIPS_assumed_shape_dopetype = 0x2010,
++ DW_AT_MIPS_assumed_size = 0x2011,
+
+- _default_ = Pass,
++ DW_AT_sf_names = 0x2101,
++ DW_AT_src_info = 0x2102,
++ DW_AT_mac_info = 0x2103,
++ DW_AT_src_coords = 0x2104,
++ DW_AT_body_begin = 0x2105,
++ DW_AT_body_end = 0x2106,
++ DW_AT_GNU_vector = 0x2107,
++ DW_AT_GNU_template_name = 0x2110,
++
++ DW_AT_GNU_call_site_value = 0x2111,
++ DW_AT_GNU_call_site_data_value = 0x2112,
++ DW_AT_GNU_call_site_target = 0x2113,
++ DW_AT_GNU_call_site_target_clobbered = 0x2114,
++ DW_AT_GNU_tail_call = 0x2115,
++ DW_AT_GNU_all_tail_call_sites = 0x2116,
++ DW_AT_GNU_all_call_sites = 0x2117,
++ DW_AT_GNU_all_source_call_sites = 0x2118,
++
++ DW_AT_APPLE_optimized = 0x3fe1,
++ DW_AT_APPLE_flags = 0x3fe2,
++ DW_AT_APPLE_isa = 0x3fe3,
++ DW_AT_APPLE_block = 0x3fe4,
++ DW_AT_APPLE_major_runtime_vers = 0x3fe5,
++ DW_AT_APPLE_runtime_class = 0x3fe6,
++ DW_AT_APPLE_omit_frame_ptr = 0x3fe7,
++ DW_AT_APPLE_property_name = 0x3fe8,
++ DW_AT_APPLE_property_getter = 0x3fe9,
++ DW_AT_APPLE_property_setter = 0x3fea,
++ DW_AT_APPLE_property_attribute = 0x3feb,
++ DW_AT_APPLE_objc_complete_type = 0x3fec,
++ DW_AT_APPLE_property = 0x3fed,
++
++ _default_ = Pass,
+ )
+
+
+@@ -225,6 +265,10 @@
+ DW_FORM_ref8 = 0x14,
+ DW_FORM_ref_udata = 0x15,
+ DW_FORM_indirect = 0x16,
++ DW_FORM_sec_offset = 0x17,
++ DW_FORM_exprloc = 0x18,
++ DW_FORM_flag_present = 0x19,
++ DW_FORM_ref_sig8 = 0x20,
+
+ _default_ = Pass,
+ )
+diff -r 249a5ca85159 elftools/dwarf/lineprogram.py
+--- a/elftools/dwarf/lineprogram.py Wed Apr 17 05:57:58 2013 -0700
++++ b/elftools/dwarf/lineprogram.py Mon Jun 03 17:52:42 2013 +0200
+@@ -215,10 +215,10 @@
+ add_entry_old_state(opcode, [operand])
+ elif opcode == DW_LNS_negate_stmt:
+ state.is_stmt = not state.is_stmt
+- add_entry_old_state(opcode, [operand])
++ add_entry_old_state(opcode, [])
+ elif opcode == DW_LNS_set_basic_block:
+ state.basic_block = True
+- add_entry_old_state(opcode, [operand])
++ add_entry_old_state(opcode, [])
+ elif opcode == DW_LNS_const_add_pc:
+ adjusted_opcode = 255 - self['opcode_base']
+ address_addend = ((adjusted_opcode // self['line_range']) *
+diff -r 249a5ca85159 elftools/dwarf/structs.py
+--- a/elftools/dwarf/structs.py Wed Apr 17 05:57:58 2013 -0700
++++ b/elftools/dwarf/structs.py Mon Jun 03 17:52:42 2013 +0200
+@@ -11,7 +11,7 @@
+ UBInt8, UBInt16, UBInt32, UBInt64, ULInt8, ULInt16, ULInt32, ULInt64,
+ SBInt8, SBInt16, SBInt32, SBInt64, SLInt8, SLInt16, SLInt32, SLInt64,
+ Adapter, Struct, ConstructError, If, RepeatUntil, Field, Rename, Enum,
+- Array, PrefixedArray, CString, Embed,
++ Array, PrefixedArray, CString, Embed, StaticField
+ )
+ from ..common.construct_utils import RepeatUntilExcluding
+
+@@ -19,39 +19,39 @@
+
+
+ class DWARFStructs(object):
+- """ Exposes Construct structs suitable for parsing information from DWARF
++ """ Exposes Construct structs suitable for parsing information from DWARF
+ sections. Each compile unit in DWARF info can have its own structs
+- object. Keep in mind that these structs have to be given a name (by
++ object. Keep in mind that these structs have to be given a name (by
+ calling them with a name) before being used for parsing (like other
+ Construct structs). Those that should be used without a name are marked
+ by (+).
+-
++
+ Accessible attributes (mostly as described in chapter 7 of the DWARF
+ spec v3):
+-
++
+ Dwarf_[u]int{8,16,32,64):
+ Data chunks of the common sizes
+-
++
+ Dwarf_offset:
+ 32-bit or 64-bit word, depending on dwarf_format
+-
++
+ Dwarf_target_addr:
+ 32-bit or 64-bit word, depending on address size
+-
++
+ Dwarf_initial_length:
+ "Initial length field" encoding
+ section 7.4
+-
++
+ Dwarf_{u,s}leb128:
+ ULEB128 and SLEB128 variable-length encoding
+-
++
+ Dwarf_CU_header (+):
+ Compilation unit header
+-
++
+ Dwarf_abbrev_declaration (+):
+ Abbreviation table declaration - doesn't include the initial
+ code, only the contents.
+-
++
+ Dwarf_dw_form (+):
+ A dictionary mapping 'DW_FORM_*' keys into construct Structs
+ that parse such forms. These Structs have already been given
+@@ -62,7 +62,7 @@
+
+ Dwarf_lineprog_file_entry (+):
+ A single file entry in a line program header or instruction
+-
++
+ Dwarf_CIE_header (+):
+ A call-frame CIE
+
+@@ -71,22 +71,27 @@
+
+ See also the documentation of public methods.
+ """
+- def __init__(self, little_endian, dwarf_format, address_size):
+- """ little_endian:
++ def __init__(self,
++ little_endian, dwarf_format, address_size, dwarf_version=2):
++ """ dwarf_version:
++ Numeric DWARF version
++
++ little_endian:
+ True if the file is little endian, False if big
+-
++
+ dwarf_format:
+ DWARF Format: 32 or 64-bit (see spec section 7.4)
+-
++
+ address_size:
+- Target machine address size, in bytes (4 or 8). (See spec
++ Target machine address size, in bytes (4 or 8). (See spec
+ section 7.5.1)
+ """
+ assert dwarf_format == 32 or dwarf_format == 64
+ assert address_size == 8 or address_size == 4
+ self.little_endian = little_endian
+- self.dwarf_format = dwarf_format
++ self.dwarf_format = dwarf_format
+ self.address_size = address_size
++ self.dwarf_version = dwarf_version
+ self._create_structs()
+
+ def initial_length_field_size(self):
+@@ -131,7 +136,7 @@
+ def _create_initial_length(self):
+ def _InitialLength(name):
+ # Adapts a Struct that parses forward a full initial length field.
+- # Only if the first word is the continuation value, the second
++ # Only if the first word is the continuation value, the second
+ # word is parsed from the stream.
+ #
+ return _InitialLengthAdapter(
+@@ -152,13 +157,13 @@
+ self.Dwarf_uint16('version'),
+ self.Dwarf_offset('debug_abbrev_offset'),
+ self.Dwarf_uint8('address_size'))
+-
++
+ def _create_abbrev_declaration(self):
+ self.Dwarf_abbrev_declaration = Struct('Dwarf_abbrev_entry',
+ Enum(self.Dwarf_uleb128('tag'), **ENUM_DW_TAG),
+ Enum(self.Dwarf_uint8('children_flag'), **ENUM_DW_CHILDREN),
+ RepeatUntilExcluding(
+- lambda obj, ctx:
++ lambda obj, ctx:
+ obj.name == 'DW_AT_null' and obj.form == 'DW_FORM_null',
+ Struct('attr_spec',
+ Enum(self.Dwarf_uleb128('name'), **ENUM_DW_AT),
+@@ -167,12 +172,12 @@
+ def _create_dw_form(self):
+ self.Dwarf_dw_form = dict(
+ DW_FORM_addr=self.Dwarf_target_addr(''),
+-
++
+ DW_FORM_block1=self._make_block_struct(self.Dwarf_uint8),
+ DW_FORM_block2=self._make_block_struct(self.Dwarf_uint16),
+ DW_FORM_block4=self._make_block_struct(self.Dwarf_uint32),
+ DW_FORM_block=self._make_block_struct(self.Dwarf_uleb128),
+-
++
+ # All DW_FORM_data<n> forms are assumed to be unsigned
+ DW_FORM_data1=self.Dwarf_uint8(''),
+ DW_FORM_data2=self.Dwarf_uint16(''),
+@@ -180,19 +185,25 @@
+ DW_FORM_data8=self.Dwarf_uint64(''),
+ DW_FORM_sdata=self.Dwarf_sleb128(''),
+ DW_FORM_udata=self.Dwarf_uleb128(''),
+-
++
+ DW_FORM_string=CString(''),
+ DW_FORM_strp=self.Dwarf_offset(''),
+ DW_FORM_flag=self.Dwarf_uint8(''),
+-
++
+ DW_FORM_ref1=self.Dwarf_uint8(''),
+ DW_FORM_ref2=self.Dwarf_uint16(''),
+ DW_FORM_ref4=self.Dwarf_uint32(''),
+ DW_FORM_ref8=self.Dwarf_uint64(''),
+ DW_FORM_ref_udata=self.Dwarf_uleb128(''),
+ DW_FORM_ref_addr=self.Dwarf_offset(''),
+-
++
+ DW_FORM_indirect=self.Dwarf_uleb128(''),
++
++ # New forms in DWARFv4
++ DW_FORM_flag_present = StaticField('', 0),
++ DW_FORM_sec_offset = self.Dwarf_offset(''),
++ DW_FORM_exprloc = self._make_block_struct(self.Dwarf_uleb128),
++ DW_FORM_ref_sig8 = self.Dwarf_offset(''),
+ )
+
+ def _create_lineprog_header(self):
+@@ -215,7 +226,7 @@
+ self.Dwarf_int8('line_base'),
+ self.Dwarf_uint8('line_range'),
+ self.Dwarf_uint8('opcode_base'),
+- Array(lambda ctx: ctx['opcode_base'] - 1,
++ Array(lambda ctx: ctx['opcode_base'] - 1,
+ self.Dwarf_uint8('standard_opcode_lengths')),
+ RepeatUntilExcluding(
+ lambda obj, ctx: obj == b'',
+@@ -226,14 +237,27 @@
+ )
+
+ def _create_callframe_entry_headers(self):
+- self.Dwarf_CIE_header = Struct('Dwarf_CIE_header',
+- self.Dwarf_initial_length('length'),
+- self.Dwarf_offset('CIE_id'),
+- self.Dwarf_uint8('version'),
+- CString('augmentation'),
+- self.Dwarf_uleb128('code_alignment_factor'),
+- self.Dwarf_sleb128('data_alignment_factor'),
+- self.Dwarf_uleb128('return_address_register'))
++ # The CIE header was modified in DWARFv4.
++ if self.dwarf_version == 4:
++ self.Dwarf_CIE_header = Struct('Dwarf_CIE_header',
++ self.Dwarf_initial_length('length'),
++ self.Dwarf_offset('CIE_id'),
++ self.Dwarf_uint8('version'),
++ CString('augmentation'),
++ self.Dwarf_uint8('address_size'),
++ self.Dwarf_uint8('segment_size'),
++ self.Dwarf_uleb128('code_alignment_factor'),
++ self.Dwarf_sleb128('data_alignment_factor'),
++ self.Dwarf_uleb128('return_address_register'))
++ else:
++ self.Dwarf_CIE_header = Struct('Dwarf_CIE_header',
++ self.Dwarf_initial_length('length'),
++ self.Dwarf_offset('CIE_id'),
++ self.Dwarf_uint8('version'),
++ CString('augmentation'),
++ self.Dwarf_uleb128('code_alignment_factor'),
++ self.Dwarf_sleb128('data_alignment_factor'),
++ self.Dwarf_uleb128('return_address_register'))
+
+ self.Dwarf_FDE_header = Struct('Dwarf_FDE_header',
+ self.Dwarf_initial_length('length'),
+@@ -242,7 +266,7 @@
+ self.Dwarf_target_addr('address_range'))
+
+ def _make_block_struct(self, length_field):
+- """ Create a struct for DW_FORM_block<size>
++ """ Create a struct for DW_FORM_block<size>
+ """
+ return PrefixedArray(
+ subcon=self.Dwarf_uint8('elem'),
+diff -r 249a5ca85159 elftools/elf/constants.py
+--- a/elftools/elf/constants.py Wed Apr 17 05:57:58 2013 -0700
++++ b/elftools/elf/constants.py Mon Jun 03 17:52:42 2013 +0200
+@@ -45,3 +45,25 @@
+ PF_MASKOS=0x00FF0000
+ PF_MASKPROC=0xFF000000
+
++
++# symbol info flags for entries
++# in the .SUNW_syminfo section
++class SUNW_SYMINFO_FLAGS(object):
++ """ Flags for the si_flags field of entries
++ in the .SUNW_syminfo section
++ """
++ SYMINFO_FLG_DIRECT=0x1
++ SYMINFO_FLG_FILTER=0x2
++ SYMINFO_FLG_COPY=0x4
++ SYMINFO_FLG_LAZYLOAD=0x8
++ SYMINFO_FLG_DIRECTBIND=0x10
++ SYMINFO_FLG_NOEXTDIRECT=0x20
++ SYMINFO_FLG_AUXILIARY=0x40
++ SYMINFO_FLG_INTERPOSE=0x80
++ SYMINFO_FLG_CAP=0x100
++ SYMINFO_FLG_DEFERRED=0x200
++
++class VER_FLAGS(object):
++ VER_FLG_BASE=0x1
++ VER_FLG_WEAK=0x2
++ VER_FLG_INFO=0x4
+diff -r 249a5ca85159 elftools/elf/descriptions.py
+--- a/elftools/elf/descriptions.py Wed Apr 17 05:57:58 2013 -0700
++++ b/elftools/elf/descriptions.py Mon Jun 03 17:52:42 2013 +0200
+@@ -9,7 +9,7 @@
+ from .enums import (
+ ENUM_D_TAG, ENUM_E_VERSION, ENUM_RELOC_TYPE_i386, ENUM_RELOC_TYPE_x64
+ )
+-from .constants import P_FLAGS, SH_FLAGS
++from .constants import P_FLAGS, SH_FLAGS, SUNW_SYMINFO_FLAGS, VER_FLAGS
+ from ..common.py3compat import iteritems
+
+
+@@ -84,6 +84,28 @@
+ return _DESCR_D_TAG.get(x, _unknown)
+
+
++def describe_syminfo_flags(x):
++ return ''.join(_DESCR_SYMINFO_FLAGS[flag] for flag in (
++ SUNW_SYMINFO_FLAGS.SYMINFO_FLG_CAP,
++ SUNW_SYMINFO_FLAGS.SYMINFO_FLG_DIRECT,
++ SUNW_SYMINFO_FLAGS.SYMINFO_FLG_FILTER,
++ SUNW_SYMINFO_FLAGS.SYMINFO_FLG_AUXILIARY,
++ SUNW_SYMINFO_FLAGS.SYMINFO_FLG_DIRECTBIND,
++ SUNW_SYMINFO_FLAGS.SYMINFO_FLG_COPY,
++ SUNW_SYMINFO_FLAGS.SYMINFO_FLG_LAZYLOAD,
++ SUNW_SYMINFO_FLAGS.SYMINFO_FLG_NOEXTDIRECT,
++ SUNW_SYMINFO_FLAGS.SYMINFO_FLG_INTERPOSE,
++ SUNW_SYMINFO_FLAGS.SYMINFO_FLG_DEFERRED) if x & flag)
++
++def describe_symbol_boundto(x):
++ return _DESCR_SYMINFO_BOUNDTO.get(x, '%3s' % x)
++
++def describe_ver_flags(x):
++ return ' | '.join(_DESCR_VER_FLAGS[flag] for flag in (
++ VER_FLAGS.VER_FLG_WEAK,
++ VER_FLAGS.VER_FLG_BASE,
++ VER_FLAGS.VER_FLG_INFO) if x & flag)
++
+ #-------------------------------------------------------------------------------
+ _unknown = '<unknown>'
+
+@@ -236,6 +258,33 @@
+ SHN_COMMON='COM',
+ )
+
++_DESCR_SYMINFO_FLAGS = {
++ SUNW_SYMINFO_FLAGS.SYMINFO_FLG_DIRECT: 'D',
++ SUNW_SYMINFO_FLAGS.SYMINFO_FLG_DIRECTBIND: 'B',
++ SUNW_SYMINFO_FLAGS.SYMINFO_FLG_COPY: 'C',
++ SUNW_SYMINFO_FLAGS.SYMINFO_FLG_LAZYLOAD: 'L',
++ SUNW_SYMINFO_FLAGS.SYMINFO_FLG_NOEXTDIRECT: 'N',
++ SUNW_SYMINFO_FLAGS.SYMINFO_FLG_AUXILIARY: 'A',
++ SUNW_SYMINFO_FLAGS.SYMINFO_FLG_FILTER: 'F',
++ SUNW_SYMINFO_FLAGS.SYMINFO_FLG_INTERPOSE: 'I',
++ SUNW_SYMINFO_FLAGS.SYMINFO_FLG_CAP: 'S',
++ SUNW_SYMINFO_FLAGS.SYMINFO_FLG_DEFERRED: 'P',
++}
++
++_DESCR_SYMINFO_BOUNDTO = dict(
++ SYMINFO_BT_SELF='<self>',
++ SYMINFO_BT_PARENT='<parent>',
++ SYMINFO_BT_NONE='',
++ SYMINFO_BT_EXTERN='<extern>',
++)
++
++_DESCR_VER_FLAGS = {
++ 0: '',
++ VER_FLAGS.VER_FLG_BASE: 'BASE',
++ VER_FLAGS.VER_FLG_WEAK: 'WEAK',
++ VER_FLAGS.VER_FLG_INFO: 'INFO',
++}
++
+ _DESCR_RELOC_TYPE_i386 = dict(
+ (v, k) for k, v in iteritems(ENUM_RELOC_TYPE_i386))
+
+diff -r 249a5ca85159 elftools/elf/dynamic.py
+--- a/elftools/elf/dynamic.py Wed Apr 17 05:57:58 2013 -0700
++++ b/elftools/elf/dynamic.py Mon Jun 03 17:52:42 2013 +0200
+@@ -25,7 +25,8 @@
+ value of DT_SONAME (fetched from the dynamic symbol table).
+ """
+ _HANDLED_TAGS = frozenset(
+- ['DT_NEEDED', 'DT_RPATH', 'DT_RUNPATH', 'DT_SONAME'])
++ ['DT_NEEDED', 'DT_RPATH', 'DT_RUNPATH', 'DT_SONAME',
++ 'DT_SUNW_FILTER'])
+
+ def __init__(self, entry, elffile):
+ self.entry = entry
+diff -r 249a5ca85159 elftools/elf/elffile.py
+--- a/elftools/elf/elffile.py Wed Apr 17 05:57:58 2013 -0700
++++ b/elftools/elf/elffile.py Mon Jun 03 17:52:42 2013 +0200
+@@ -12,9 +12,13 @@
+ from ..construct import ConstructError
+ from .structs import ELFStructs
+ from .sections import (
+- Section, StringTableSection, SymbolTableSection, NullSection)
++ Section, StringTableSection, SymbolTableSection,
++ SUNWSyminfoTableSection, NullSection)
+ from .dynamic import DynamicSection, DynamicSegment
+ from .relocation import RelocationSection, RelocationHandler
++from .gnuversions import (
++ GNUVerNeedSection, GNUVerDefSection,
++ GNUVerSymSection)
+ from .segments import Segment, InterpSegment
+ from .enums import ENUM_RELOC_TYPE_i386, ENUM_RELOC_TYPE_x64
+ from ..dwarf.dwarfinfo import DWARFInfo, DebugSectionDescriptor, DwarfConfig
+@@ -125,15 +129,15 @@
+ #
+ debug_sections = {}
+ for secname in (b'.debug_info', b'.debug_abbrev', b'.debug_str',
+- b'.debug_line', b'.debug_frame', b'.debug_loc',
+- b'.debug_ranges'):
++ b'.debug_line', b'.debug_frame',
++ b'.debug_loc', b'.debug_ranges'):
+ section = self.get_section_by_name(secname)
+ if section is None:
+ debug_sections[secname] = None
+ else:
+ debug_sections[secname] = self._read_dwarf_section(
+- section,
+- relocate_dwarf_sections)
++ section,
++ relocate_dwarf_sections)
+
+ return DWARFInfo(
+ config=DwarfConfig(
+@@ -143,6 +147,8 @@
+ debug_info_sec=debug_sections[b'.debug_info'],
+ debug_abbrev_sec=debug_sections[b'.debug_abbrev'],
+ debug_frame_sec=debug_sections[b'.debug_frame'],
++ # TODO(eliben): reading of eh_frame is not hooked up yet
++ eh_frame_sec=None,
+ debug_str_sec=debug_sections[b'.debug_str'],
+ debug_loc_sec=debug_sections[b'.debug_loc'],
+ debug_ranges_sec=debug_sections[b'.debug_ranges'],
+@@ -243,6 +249,14 @@
+ return NullSection(section_header, name, self.stream)
+ elif sectype in ('SHT_SYMTAB', 'SHT_DYNSYM'):
+ return self._make_symbol_table_section(section_header, name)
++ elif sectype == 'SHT_SUNW_syminfo':
++ return self._make_sunwsyminfo_table_section(section_header, name)
++ elif sectype == 'SHT_GNU_verneed':
++ return self._make_gnu_verneed_section(section_header, name)
++ elif sectype == 'SHT_GNU_verdef':
++ return self._make_gnu_verdef_section(section_header, name)
++ elif sectype == 'SHT_GNU_versym':
++ return self._make_gnu_versym_section(section_header, name)
+ elif sectype in ('SHT_REL', 'SHT_RELA'):
+ return RelocationSection(
+ section_header, name, self.stream, self)
+@@ -261,6 +275,46 @@
+ elffile=self,
+ stringtable=strtab_section)
+
++ def _make_sunwsyminfo_table_section(self, section_header, name):
++ """ Create a SUNWSyminfoTableSection
++ """
++ linked_strtab_index = section_header['sh_link']
++ strtab_section = self.get_section(linked_strtab_index)
++ return SUNWSyminfoTableSection(
++ section_header, name, self.stream,
++ elffile=self,
++ symboltable=strtab_section)
++
++ def _make_gnu_verneed_section(self, section_header, name):
++ """ Create a GNUVerNeedSection
++ """
++ linked_strtab_index = section_header['sh_link']
++ strtab_section = self.get_section(linked_strtab_index)
++ return GNUVerNeedSection(
++ section_header, name, self.stream,
++ elffile=self,
++ stringtable=strtab_section)
++
++ def _make_gnu_verdef_section(self, section_header, name):
++ """ Create a GNUVerDefSection
++ """
++ linked_strtab_index = section_header['sh_link']
++ strtab_section = self.get_section(linked_strtab_index)
++ return GNUVerDefSection(
++ section_header, name, self.stream,
++ elffile=self,
++ stringtable=strtab_section)
++
++ def _make_gnu_versym_section(self, section_header, name):
++ """ Create a GNUVerSymSection
++ """
++ linked_strtab_index = section_header['sh_link']
++ strtab_section = self.get_section(linked_strtab_index)
++ return GNUVerSymSection(
++ section_header, name, self.stream,
++ elffile=self,
++ symboltable=strtab_section)
++
+ def _get_segment_header(self, n):
+ """ Find the header of segment #n, parse it and return the struct
+ """
+diff -r 249a5ca85159 elftools/elf/enums.py
+--- a/elftools/elf/enums.py Wed Apr 17 05:57:58 2013 -0700
++++ b/elftools/elf/enums.py Mon Jun 03 17:52:42 2013 +0200
+@@ -184,14 +184,15 @@
+ SHT_NUM=19,
+ SHT_LOOS=0x60000000,
+ SHT_GNU_HASH=0x6ffffff6,
+- SHT_GNU_verdef=0x6ffffffd,
+- SHT_GNU_verneed=0x6ffffffe,
+- SHT_GNU_versym=0x6fffffff,
++ SHT_GNU_verdef=0x6ffffffd, # also SHT_SUNW_verdef
++ SHT_GNU_verneed=0x6ffffffe, # also SHT_SUNW_verneed
++ SHT_GNU_versym=0x6fffffff, # also SHT_SUNW_versym
+ SHT_LOPROC=0x70000000,
+ SHT_HIPROC=0x7fffffff,
+ SHT_LOUSER=0x80000000,
+ SHT_HIUSER=0xffffffff,
+ SHT_AMD64_UNWIND=0x70000001,
++ SHT_SUNW_syminfo=0x6ffffffc,
+ _default_=Pass,
+ )
+
+@@ -301,6 +302,24 @@
+ DT_PREINIT_ARRAYSZ=33,
+ DT_NUM=34,
+ DT_LOOS=0x6000000d,
++ DT_SUNW_AUXILIARY=0x6000000d,
++ DT_SUNW_RTLDINF=0x6000000e,
++ DT_SUNW_FILTER=0x6000000f,
++ DT_SUNW_CAP=0x60000010,
++ DT_SUNW_SYMTAB=0x60000011,
++ DT_SUNW_SYMSZ=0x60000012,
++ DT_SUNW_ENCODING=0x60000013,
++ DT_SUNW_SORTENT=0x60000013,
++ DT_SUNW_SYMSORT=0x60000014,
++ DT_SUNW_SYMSORTSZ=0x60000015,
++ DT_SUNW_TLSSORT=0x60000016,
++ DT_SUNW_TLSSORTSZ=0x60000017,
++ DT_SUNW_CAPINFO=0x60000018,
++ DT_SUNW_STRPAD=0x60000019,
++ DT_SUNW_CAPCHAIN=0x6000001a,
++ DT_SUNW_LDMACH=0x6000001b,
++ DT_SUNW_CAPCHAINENT=0x6000001d,
++ DT_SUNW_CAPCHAINSZ=0x6000001f,
+ DT_HIOS=0x6ffff000,
+ DT_LOPROC=0x70000000,
+ DT_HIPROC=0x7fffffff,
+@@ -428,3 +447,29 @@
+ _default_=Pass,
+ )
+
++# Sunw Syminfo Bound To special values
++ENUM_SUNW_SYMINFO_BOUNDTO = dict(
++ SYMINFO_BT_SELF=0xffff,
++ SYMINFO_BT_PARENT=0xfffe,
++ SYMINFO_BT_NONE=0xfffd,
++ SYMINFO_BT_EXTERN=0xfffc,
++ _default_=Pass,
++)
++
++# Versym section, version dependency index
++ENUM_VERSYM = dict(
++ VER_NDX_LOCAL=0,
++ VER_NDX_GLOBAL=1,
++ VER_NDX_LORESERVE=0xff00,
++ VER_NDX_ELIMINATE=0xff01,
++ _default_=Pass,
++)
++# Sunw Syminfo Bound To special values
++ENUM_SUNW_SYMINFO_BOUNDTO = dict(
++ SYMINFO_BT_SELF=0xffff,
++ SYMINFO_BT_PARENT=0xfffe,
++ SYMINFO_BT_NONE=0xfffd,
++ SYMINFO_BT_EXTERN=0xfffc,
++ _default_=Pass,
++)
++
+diff -r 249a5ca85159 elftools/elf/gnuversions.py
+--- /dev/null Thu Jan 01 00:00:00 1970 +0000
++++ b/elftools/elf/gnuversions.py Mon Jun 03 17:52:42 2013 +0200
+@@ -0,0 +1,228 @@
++#------------------------------------------------------------------------------
++# elftools: elf/gnuversions.py
++#
++# ELF sections
++#
++# Yann Rouillard (yann at pleiades.fr.eu.org)
++# This code is in the public domain
++#------------------------------------------------------------------------------
++from ..construct import CString
++from ..common.utils import struct_parse, elf_assert
++from .sections import Section, Symbol
++
++
++class Version(object):
++ """ Version object - representing a version definition or dependency
++ entry from a "Version Needed" or a "Version Dependency" table section.
++
++ This kind of entry contains a pointer to an array of auxiliary entries
++ that store the information about version names or dependencies.
++ These entries are not stored in this object and should be accessed
++ through the appropriate method of a section object which will return
++ an iterator of VersionAuxiliary objects.
++
++ Similarly to Section objects, allows dictionary-like access to
++ verdef/verneed entry
++ """
++ def __init__(self, entry, name=None):
++ self.entry = entry
++ self.name = name
++
++ def __getitem__(self, name):
++ """ Implement dict-like access to entry
++ """
++ return self.entry[name]
++
++
++class VersionAuxiliary(object):
++ """ Version Auxiliary object - representing an auxiliary entry of a version
++ definition or dependency entry
++
++ Similarly to Section objects, allows dictionary-like access to the
++ verdaux/vernaux entry
++ """
++ def __init__(self, entry, name):
++ self.entry = entry
++ self.name = name
++
++ def __getitem__(self, name):
++ """ Implement dict-like access to entries
++ """
++ return self.entry[name]
++
++
++class GNUVersionSection(Section):
++ """ Common ancestor class for ELF SUNW|GNU Version Needed/Dependency
++ sections class which contains shareable code
++ """
++
++ def __init__(self, header, name, stream, elffile, stringtable,
++ field_prefix, version_struct, version_auxiliaries_struct):
++ super(GNUVersionSection, self).__init__(header, name, stream)
++ self.elffile = elffile
++ self.stringtable = stringtable
++ self.field_prefix = field_prefix
++ self.version_struct = version_struct
++ self.version_auxiliaries_struct = version_auxiliaries_struct
++
++ def num_versions(self):
++ """ Number of version entries in the section
++ """
++ return self['sh_info']
++
++ def _field_name(self, name, auxiliary=False):
++ """ Return the real field's name of version or a version auxiliary
++ entry
++ """
++ middle = 'a_' if auxiliary else '_'
++ return self.field_prefix + middle + name
++
++ def _iter_version_auxiliaries(self, entry_offset, count):
++ """ Yield all auxiliary entries of a version entry
++ """
++ name_field = self._field_name('name', auxiliary=True)
++ next_field = self._field_name('next', auxiliary=True)
++
++ for _ in range(count):
++ entry = struct_parse(
++ self.version_auxiliaries_struct,
++ self.stream,
++ stream_pos=entry_offset)
++
++ name = self.stringtable.get_string(entry[name_field])
++ version_aux = VersionAuxiliary(entry, name)
++ yield version_aux
++
++ entry_offset += entry[next_field]
++
++ def iter_versions(self):
++ """ Yield all the version entries in the section
++ Each time it returns the main version structure
++ and an iterator to walk through its auxiliaries entries
++ """
++ aux_field = self._field_name('aux')
++ count_field = self._field_name('cnt')
++ next_field = self._field_name('next')
++
++ entry_offset = self['sh_offset']
++ for _ in range(self.num_versions()):
++ entry = struct_parse(
++ self.version_struct,
++ self.stream,
++ stream_pos=entry_offset)
++
++ elf_assert(entry[count_field] > 0,
++ 'Expected number of version auxiliary entries (%s) to be > 0'
++ 'for the following version entry: %s' % (
++ count_field, str(entry)))
++
++ version = Version(entry)
++ aux_entries_offset = entry_offset + entry[aux_field]
++ version_auxiliaries_iter = self._iter_version_auxiliaries(
++ aux_entries_offset, entry[count_field])
++
++ yield version, version_auxiliaries_iter
++
++ entry_offset += entry[next_field]
++
++
++class GNUVerNeedSection(GNUVersionSection):
++ """ ELF SUNW or GNU Version Needed table section.
++ Has an associated StringTableSection that's passed in the constructor.
++ """
++ def __init__(self, header, name, stream, elffile, stringtable):
++ super(GNUVerNeedSection, self).__init__(
++ header, name, stream, elffile, stringtable, 'vn',
++ elffile.structs.Elf_Verneed, elffile.structs.Elf_Vernaux)
++ self._has_indexes = None
++
++ def has_indexes(self):
++ """ Return True if at least one version definition entry has an index
++ that is stored in the vna_other field.
++ This information is used for symbol versioning
++ """
++ if self._has_indexes is None:
++ self._has_indexes = False
++ for _, vernaux_iter in self.iter_versions():
++ for vernaux in vernaux_iter:
++ if vernaux['vna_other']:
++ self._has_indexes = True
++ break
++
++ return self._has_indexes
++
++ def iter_versions(self):
++ for verneed, vernaux in super(GNUVerNeedSection, self).iter_versions():
++ verneed.name = self.stringtable.get_string(verneed['vn_file'])
++ yield verneed, vernaux
++
++ def get_version(self, index):
++ """ Get the version information located at index #n in the table
++ Return boths the verneed structure and the vernaux structure
++ that contains the name of the version
++ """
++ for verneed, vernaux_iter in self.iter_versions():
++ for vernaux in vernaux_iter:
++ if vernaux['vna_other'] == index:
++ return verneed, vernaux
++
++ return None
++
++
++class GNUVerDefSection(GNUVersionSection):
++ """ ELF SUNW or GNU Version Definition table section.
++ Has an associated StringTableSection that's passed in the constructor.
++ """
++ def __init__(self, header, name, stream, elffile, stringtable):
++ super(GNUVerDefSection, self).__init__(
++ header, name, stream, elffile, stringtable, 'vd',
++ elffile.structs.Elf_Verdef, elffile.structs.Elf_Verdaux)
++
++ def get_version(self, index):
++ """ Get the version information located at index #n in the table
++ Return boths the verdef structure and an iterator to retrieve
++ both the version names and dependencies in the form of
++ verdaux entries
++ """
++ for verdef, verdaux_iter in self.iter_versions():
++ if verdef['vd_ndx'] == index:
++ return verdef, verdaux_iter
++
++ return None
++
++
++class GNUVerSymSection(Section):
++ """ ELF SUNW or GNU Versym table section.
++ Has an associated SymbolTableSection that's passed in the constructor.
++ """
++ def __init__(self, header, name, stream, elffile, symboltable):
++ super(GNUVerSymSection, self).__init__(header, name, stream)
++ self.elffile = elffile
++ self.elfstructs = self.elffile.structs
++ self.symboltable = symboltable
++
++ def num_symbols(self):
++ """ Number of symbols in the table
++ """
++ return self['sh_size'] // self['sh_entsize']
++
++ def get_symbol(self, n):
++ """ Get the symbol at index #n from the table (Symbol object)
++ It begins at 1 and not 0 since the first entry is used to
++ store the current version of the syminfo table
++ """
++ # Grab the symbol's entry from the stream
++ entry_offset = self['sh_offset'] + n * self['sh_entsize']
++ entry = struct_parse(
++ self.elfstructs.Elf_Versym,
++ self.stream,
++ stream_pos=entry_offset)
++ # Find the symbol name in the associated symbol table
++ name = self.symboltable.get_symbol(n).name
++ return Symbol(entry, name)
++
++ def iter_symbols(self):
++ """ Yield all the symbols in the table
++ """
++ for i in range(self.num_symbols()):
++ yield self.get_symbol(i)
+diff -r 249a5ca85159 elftools/elf/relocation.py
+--- a/elftools/elf/relocation.py Wed Apr 17 05:57:58 2013 -0700
++++ b/elftools/elf/relocation.py Mon Jun 03 17:52:42 2013 +0200
+@@ -202,6 +202,9 @@
+ def _reloc_calc_sym_plus_addend(value, sym_value, offset, addend=0):
+ return sym_value + addend
+
++ def _reloc_calc_sym_plus_addend_pcrel(value, sym_value, offset, addend=0):
++ return sym_value + addend - offset
++
+ _RELOCATION_RECIPES_X86 = {
+ ENUM_RELOC_TYPE_i386['R_386_NONE']: _RELOCATION_RECIPE_TYPE(
+ bytesize=4, has_addend=False, calc_func=_reloc_calc_identity),
+@@ -218,6 +221,9 @@
+ bytesize=8, has_addend=True, calc_func=_reloc_calc_identity),
+ ENUM_RELOC_TYPE_x64['R_X86_64_64']: _RELOCATION_RECIPE_TYPE(
+ bytesize=8, has_addend=True, calc_func=_reloc_calc_sym_plus_addend),
++ ENUM_RELOC_TYPE_x64['R_X86_64_PC32']: _RELOCATION_RECIPE_TYPE(
++ bytesize=8, has_addend=True,
++ calc_func=_reloc_calc_sym_plus_addend_pcrel),
+ ENUM_RELOC_TYPE_x64['R_X86_64_32']: _RELOCATION_RECIPE_TYPE(
+ bytesize=4, has_addend=True, calc_func=_reloc_calc_sym_plus_addend),
+ ENUM_RELOC_TYPE_x64['R_X86_64_32S']: _RELOCATION_RECIPE_TYPE(
+diff -r 249a5ca85159 elftools/elf/sections.py
+--- a/elftools/elf/sections.py Wed Apr 17 05:57:58 2013 -0700
++++ b/elftools/elf/sections.py Mon Jun 03 17:52:42 2013 +0200
+@@ -13,7 +13,7 @@
+ class Section(object):
+ """ Base class for ELF sections. Also used for all sections types that have
+ no special functionality.
+-
++
+ Allows dictionary-like access to the section header. For example:
+ > sec = Section(...)
+ > sec['sh_type'] # section type
+@@ -22,7 +22,7 @@
+ self.header = header
+ self.name = name
+ self.stream = stream
+-
++
+ def data(self):
+ """ The section data from the file.
+ """
+@@ -33,7 +33,7 @@
+ """ Is this a null section?
+ """
+ return False
+-
++
+ def __getitem__(self, name):
+ """ Implement dict-like access to header entries
+ """
+@@ -51,14 +51,14 @@
+
+ def is_null(self):
+ return True
+-
++
+
+ class StringTableSection(Section):
+ """ ELF string table section.
+ """
+ def __init__(self, header, name, stream):
+ super(StringTableSection, self).__init__(header, name, stream)
+-
++
+ def get_string(self, offset):
+ """ Get the string stored at the given offset in this string table.
+ """
+@@ -85,7 +85,7 @@
+ """ Number of symbols in the table
+ """
+ return self['sh_size'] // self['sh_entsize']
+-
++
+ def get_symbol(self, n):
+ """ Get the symbol at index #n from the table (Symbol object)
+ """
+@@ -123,3 +123,38 @@
+ return self.entry[name]
+
+
++class SUNWSyminfoTableSection(Section):
++ """ ELF .SUNW Syminfo table section.
++ Has an associated SymbolTableSection that's passed in the constructor.
++ """
++ def __init__(self, header, name, stream, elffile, symboltable):
++ super(SUNWSyminfoTableSection, self).__init__(header, name, stream)
++ self.elffile = elffile
++ self.elfstructs = self.elffile.structs
++ self.symboltable = symboltable
++
++ def num_symbols(self):
++ """ Number of symbols in the table
++ """
++ return self['sh_size'] // self['sh_entsize'] - 1
++
++ def get_symbol(self, n):
++ """ Get the symbol at index #n from the table (Symbol object).
++ It begins at 1 and not 0 since the first entry is used to
++ store the current version of the syminfo table.
++ """
++ # Grab the symbol's entry from the stream
++ entry_offset = self['sh_offset'] + n * self['sh_entsize']
++ entry = struct_parse(
++ self.elfstructs.Elf_Sunw_Syminfo,
++ self.stream,
++ stream_pos=entry_offset)
++ # Find the symbol name in the associated symbol table
++ name = self.symboltable.get_symbol(n).name
++ return Symbol(entry, name)
++
++ def iter_symbols(self):
++ """ Yield all the symbols in the table
++ """
++ for i in range(1, self.num_symbols() + 1):
++ yield self.get_symbol(i)
+diff -r 249a5ca85159 elftools/elf/structs.py
+--- a/elftools/elf/structs.py Wed Apr 17 05:57:58 2013 -0700
++++ b/elftools/elf/structs.py Mon Jun 03 17:52:42 2013 +0200
+@@ -19,20 +19,20 @@
+
+ class ELFStructs(object):
+ """ Accessible attributes:
+-
++
+ Elf_{byte|half|word|word64|addr|offset|sword|xword|xsword}:
+- Data chunks, as specified by the ELF standard, adjusted for
++ Data chunks, as specified by the ELF standard, adjusted for
+ correct endianness and word-size.
+
+ Elf_Ehdr:
+ ELF file header
+-
++
+ Elf_Phdr:
+ Program header
+-
++
+ Elf_Shdr:
+ Section header
+-
++
+ Elf_Sym:
+ Symbol table entry
+
+@@ -42,9 +42,9 @@
+ def __init__(self, little_endian=True, elfclass=32):
+ assert elfclass == 32 or elfclass == 64
+ self.little_endian = little_endian
+- self.elfclass = elfclass
++ self.elfclass = elfclass
+ self._create_structs()
+-
++
+ def _create_structs(self):
+ if self.little_endian:
+ self.Elf_byte = ULInt8
+@@ -66,14 +66,18 @@
+ self.Elf_sword = SBInt32
+ self.Elf_xword = UBInt32 if self.elfclass == 32 else UBInt64
+ self.Elf_sxword = SBInt32 if self.elfclass == 32 else SBInt64
+-
++
+ self._create_ehdr()
+ self._create_phdr()
+ self._create_shdr()
+ self._create_sym()
+ self._create_rel()
+ self._create_dyn()
+-
++ self._create_sunw_syminfo()
++ self._create_gnu_verneed()
++ self._create_gnu_verdef()
++ self._create_gnu_versym()
++
+ def _create_ehdr(self):
+ self.Elf_Ehdr = Struct('Elf_Ehdr',
+ Struct('e_ident',
+@@ -99,7 +103,7 @@
+ self.Elf_half('e_shnum'),
+ self.Elf_half('e_shstrndx'),
+ )
+-
++
+ def _create_phdr(self):
+ if self.elfclass == 32:
+ self.Elf_Phdr = Struct('Elf_Phdr',
+@@ -122,8 +126,8 @@
+ self.Elf_xword('p_filesz'),
+ self.Elf_xword('p_memsz'),
+ self.Elf_xword('p_align'),
+- )
+-
++ )
++
+ def _create_shdr(self):
+ self.Elf_Shdr = Struct('Elf_Shdr',
+ self.Elf_word('sh_name'),
+@@ -137,7 +141,7 @@
+ self.Elf_xword('sh_addralign'),
+ self.Elf_xword('sh_entsize'),
+ )
+-
++
+ def _create_rel(self):
+ # r_info is also taken apart into r_info_sym and r_info_type.
+ # This is done in Value to avoid endianity issues while parsing.
+@@ -203,5 +207,50 @@
+ self.Elf_xword('st_size'),
+ )
+
++ def _create_sunw_syminfo(self):
++ self.Elf_Sunw_Syminfo = Struct('Elf_Sunw_Syminfo',
++ Enum(self.Elf_half('si_boundto'), **ENUM_SUNW_SYMINFO_BOUNDTO),
++ self.Elf_half('si_flags'),
++ )
+
++ def _create_gnu_verneed(self):
++ # Structure of "version needed" entries is documented in
++ # Oracle "Linker and Libraries Guide", Chapter 7 Object File Format
++ self.Elf_Verneed = Struct('Elf_Verneed',
++ self.Elf_half('vn_version'),
++ self.Elf_half('vn_cnt'),
++ self.Elf_word('vn_file'),
++ self.Elf_word('vn_aux'),
++ self.Elf_word('vn_next'),
++ )
++ self.Elf_Vernaux = Struct('Elf_Vernaux',
++ self.Elf_word('vna_hash'),
++ self.Elf_half('vna_flags'),
++ self.Elf_half('vna_other'),
++ self.Elf_word('vna_name'),
++ self.Elf_word('vna_next'),
++ )
+
++ def _create_gnu_verdef(self):
++ # Structure off "version definition" entries are documented in
++ # Oracle "Linker and Libraries Guide", Chapter 7 Object File Format
++ self.Elf_Verdef = Struct('Elf_Verdef',
++ self.Elf_half('vd_version'),
++ self.Elf_half('vd_flags'),
++ self.Elf_half('vd_ndx'),
++ self.Elf_half('vd_cnt'),
++ self.Elf_word('vd_hash'),
++ self.Elf_word('vd_aux'),
++ self.Elf_word('vd_next'),
++ )
++ self.Elf_Verdaux = Struct('Elf_Verdaux',
++ self.Elf_word('vda_name'),
++ self.Elf_word('vda_next'),
++ )
++
++ def _create_gnu_versym(self):
++ # Structure off "version symbol" entries are documented in
++ # Oracle "Linker and Libraries Guide", Chapter 7 Object File Format
++ self.Elf_Versym = Struct('Elf_Versym',
++ Enum(self.Elf_half('ndx'), **ENUM_VERSYM),
++ )
+diff -r 249a5ca85159 scripts/readelf.py
+--- a/scripts/readelf.py Wed Apr 17 05:57:58 2013 -0700
++++ b/scripts/readelf.py Mon Jun 03 17:52:42 2013 +0200
+@@ -25,6 +25,10 @@
+ from elftools.elf.enums import ENUM_D_TAG
+ from elftools.elf.segments import InterpSegment
+ from elftools.elf.sections import SymbolTableSection
++from elftools.elf.gnuversions import (
++ GNUVerSymSection, GNUVerDefSection,
++ GNUVerNeedSection,
++ )
+ from elftools.elf.relocation import RelocationSection
+ from elftools.elf.descriptions import (
+ describe_ei_class, describe_ei_data, describe_ei_version,
+@@ -33,6 +37,7 @@
+ describe_sh_type, describe_sh_flags,
+ describe_symbol_type, describe_symbol_bind, describe_symbol_visibility,
+ describe_symbol_shndx, describe_reloc_type, describe_dyn_tag,
++ describe_ver_flags,
+ )
+ from elftools.dwarf.dwarfinfo import DWARFInfo
+ from elftools.dwarf.descriptions import (
+@@ -61,6 +66,8 @@
+ # Lazily initialized if a debug dump is requested
+ self._dwarfinfo = None
+
++ self._versioninfo = None
++
+ def display_file_header(self):
+ """ Display the ELF file header
+ """
+@@ -254,6 +261,8 @@
+ def display_symbol_tables(self):
+ """ Display the symbol tables contained in the file
+ """
++ self._init_versioninfo()
++
+ for section in self.elffile.iter_sections():
+ if not isinstance(section, SymbolTableSection):
+ continue
+@@ -272,16 +281,37 @@
+ self._emitline(' Num: Value Size Type Bind Vis Ndx Name')
+
+ for nsym, symbol in enumerate(section.iter_symbols()):
++
++ version_info = ''
++ # readelf doesn't display version info for Solaris versioning
++ if (section['sh_type'] == 'SHT_DYNSYM' and
++ self._versioninfo['type'] == 'GNU'):
++ version = self._symbol_version(nsym)
++ if (version['name'] != bytes2str(symbol.name) and
++ version['index'] not in ('VER_NDX_LOCAL',
++ 'VER_NDX_GLOBAL')):
++ if version['filename']:
++ # external symbol
++ version_info = '@%(name)s (%(index)i)' % version
++ else:
++ # internal symbol
++ if version['hidden']:
++ version_info = '@%(name)s' % version
++ else:
++ version_info = '@@%(name)s' % version
++
+ # symbol names are truncated to 25 chars, similarly to readelf
+- self._emitline('%6d: %s %5d %-7s %-6s %-7s %4s %.25s' % (
++ self._emitline('%6d: %s %5d %-7s %-6s %-7s %4s %.25s%s' % (
+ nsym,
+- self._format_hex(symbol['st_value'], fullhex=True, lead0x=False),
++ self._format_hex(
++ symbol['st_value'], fullhex=True, lead0x=False),
+ symbol['st_size'],
+ describe_symbol_type(symbol['st_info']['type']),
+ describe_symbol_bind(symbol['st_info']['bind']),
+ describe_symbol_visibility(symbol['st_other']['visibility']),
+ describe_symbol_shndx(symbol['st_shndx']),
+- bytes2str(symbol.name)))
++ bytes2str(symbol.name),
++ version_info))
+
+ def display_dynamic_tags(self):
+ """ Display the dynamic tags contained in the file
+@@ -384,6 +414,111 @@
+ if not has_relocation_sections:
+ self._emitline('\nThere are no relocations in this file.')
+
++ def display_version_info(self):
++ """ Display the version info contained in the file
++ """
++ self._init_versioninfo()
++
++ if not self._versioninfo['type']:
++ self._emitline("\nNo version information found in this file.")
++ return
++
++ for section in self.elffile.iter_sections():
++ if isinstance(section, GNUVerSymSection):
++ self._print_version_section_header(
++ section, 'Version symbols', lead0x=False)
++
++ num_symbols = section.num_symbols()
++
++ # Symbol version info are printed four by four entries
++ for idx_by_4 in range(0, num_symbols, 4):
++
++ self._emit(' %03x:' % idx_by_4)
++
++ for idx in range(idx_by_4, min(idx_by_4 + 4, num_symbols)):
++
++ symbol_version = self._symbol_version(idx)
++ if symbol_version['index'] == 'VER_NDX_LOCAL':
++ version_index = 0
++ version_name = '(*local*)'
++ elif symbol_version['index'] == 'VER_NDX_GLOBAL':
++ version_index = 1
++ version_name = '(*global*)'
++ else:
++ version_index = symbol_version['index']
++ version_name = '(%(name)s)' % symbol_version
++
++ visibility = 'h' if symbol_version['hidden'] else ' '
++
++ self._emit('%4x%s%-13s' % (
++ version_index, visibility, version_name))
++
++ self._emitline()
++
++ elif isinstance(section, GNUVerDefSection):
++ self._print_version_section_header(
++ section, 'Version definition', indent=2)
++
++ offset = 0
++ for verdef, verdaux_iter in section.iter_versions():
++ verdaux = next(verdaux_iter)
++
++ name = verdaux.name
++ if verdef['vd_flags']:
++ flags = describe_ver_flags(verdef['vd_flags'])
++ # Mimic exactly the readelf output
++ flags += ' '
++ else:
++ flags = 'none'
++
++ self._emitline(' %s: Rev: %i Flags: %s Index: %i'
++ ' Cnt: %i Name: %s' % (
++ self._format_hex(offset, fieldsize=6,
++ alternate=True),
++ verdef['vd_version'], flags, verdef['vd_ndx'],
++ verdef['vd_cnt'], bytes2str(name)))
++
++ verdaux_offset = (
++ offset + verdef['vd_aux'] + verdaux['vda_next'])
++ for idx, verdaux in enumerate(verdaux_iter, start=1):
++ self._emitline(' %s: Parent %i: %s' %
++ (self._format_hex(verdaux_offset, fieldsize=4),
++ idx, bytes2str(verdaux.name)))
++ verdaux_offset += verdaux['vda_next']
++
++ offset += verdef['vd_next']
++
++ elif isinstance(section, GNUVerNeedSection):
++ self._print_version_section_header(section, 'Version needs')
++
++ offset = 0
++ for verneed, verneed_iter in section.iter_versions():
++
++ self._emitline(' %s: Version: %i File: %s Cnt: %i' % (
++ self._format_hex(offset, fieldsize=6,
++ alternate=True),
++ verneed['vn_version'], bytes2str(verneed.name),
++ verneed['vn_cnt']))
++
++ vernaux_offset = offset + verneed['vn_aux']
++ for idx, vernaux in enumerate(verneed_iter, start=1):
++ if vernaux['vna_flags']:
++ flags = describe_ver_flags(vernaux['vna_flags'])
++ # Mimic exactly the readelf output
++ flags += ' '
++ else:
++ flags = 'none'
++
++ self._emitline(
++ ' %s: Name: %s Flags: %s Version: %i' % (
++ self._format_hex(vernaux_offset, fieldsize=4),
++ bytes2str(vernaux.name), flags,
++ vernaux['vna_other']))
++
++ vernaux_offset += vernaux['vna_next']
++
++ offset += verneed['vn_next']
++
+ def display_hex_dump(self, section_spec):
+ """ Display a hex dump of a section. section_spec is either a section
+ number or a name.
+@@ -486,7 +621,8 @@
+ else:
+ self._emitline('debug dump not yet supported for "%s"' % dump_what)
+
+- def _format_hex(self, addr, fieldsize=None, fullhex=False, lead0x=True):
++ def _format_hex(self, addr, fieldsize=None, fullhex=False, lead0x=True,
++ alternate=False):
+ """ Format an address into a hexadecimal string.
+
+ fieldsize:
+@@ -501,7 +637,20 @@
+
+ lead0x:
+ If True, leading 0x is added
++
++ alternate:
++ If True, override lead0x to emulate the alternate
++ hexadecimal form specified in format string with the #
++ character: only non-zero values are prefixed with 0x.
++ This form is used by readelf.
+ """
++ if alternate:
++ if addr == 0:
++ lead0x = False
++ else:
++ lead0x = True
++ fieldsize -= 2
++
+ s = '0x' if lead0x else ''
+ if fullhex:
+ fieldsize = 8 if self.elffile.elfclass == 32 else 16
+@@ -511,6 +660,97 @@
+ field = '%' + '0%sx' % fieldsize
+ return s + field % addr
+
++ def _print_version_section_header(self, version_section, name, lead0x=True,
++ indent=1):
++ """ Print a section header of one version related section (versym,
++ verneed or verdef) with some options to accomodate readelf
++ little differences between each header (e.g. indentation
++ and 0x prefixing).
++ """
++ if hasattr(version_section, 'num_versions'):
++ num_entries = version_section.num_versions()
++ else:
++ num_entries = version_section.num_symbols()
++
++ self._emitline("\n%s section '%s' contains %s entries:" %
++ (name, bytes2str(version_section.name), num_entries))
++ self._emitline('%sAddr: %s Offset: %s Link: %i (%s)' % (
++ ' ' * indent,
++ self._format_hex(
++ version_section['sh_addr'], fieldsize=16, lead0x=lead0x),
++ self._format_hex(
++ version_section['sh_offset'], fieldsize=6, lead0x=True),
++ version_section['sh_link'],
++ bytes2str(
++ self.elffile.get_section(version_section['sh_link']).name)
++ )
++ )
++
++ def _init_versioninfo(self):
++ """ Search and initialize informations about version related sections
++ and the kind of versioning used (GNU or Solaris).
++ """
++ if self._versioninfo is not None:
++ return
++
++ self._versioninfo = {'versym': None, 'verdef': None,
++ 'verneed': None, 'type': None}
++
++ for section in self.elffile.iter_sections():
++ if isinstance(section, GNUVerSymSection):
++ self._versioninfo['versym'] = section
++ elif isinstance(section, GNUVerDefSection):
++ self._versioninfo['verdef'] = section
++ elif isinstance(section, GNUVerNeedSection):
++ self._versioninfo['verneed'] = section
++ elif isinstance(section, DynamicSection):
++ for tag in section.iter_tags():
++ if tag['d_tag'] == 'DT_VERSYM':
++ self._versioninfo['type'] = 'GNU'
++ break
++
++ if not self._versioninfo['type'] and (
++ self._versioninfo['verneed'] or self._versioninfo['verdef']):
++ self._versioninfo['type'] = 'Solaris'
++
++ def _symbol_version(self, nsym):
++ """ Return a dict containing information on the
++ or None if no version information is available
++ """
++ self._init_versioninfo()
++
++ symbol_version = dict.fromkeys(('index', 'name', 'filename', 'hidden'))
++
++ if (not self._versioninfo['versym'] or
++ nsym >= self._versioninfo['versym'].num_symbols()):
++ return None
++
++ symbol = self._versioninfo['versym'].get_symbol(nsym)
++ index = symbol.entry['ndx']
++ if not index in ('VER_NDX_LOCAL', 'VER_NDX_GLOBAL'):
++ index = int(index)
++
++ if self._versioninfo['type'] == 'GNU':
++ # In GNU versioning mode, the highest bit is used to
++ # store wether the symbol is hidden or not
++ if index & 0x8000:
++ index &= ~0x8000
++ symbol_version['hidden'] = True
++
++ if (self._versioninfo['verdef'] and
++ index <= self._versioninfo['verdef'].num_versions()):
++ _, verdaux_iter = \
++ self._versioninfo['verdef'].get_version(index)
++ symbol_version['name'] = bytes2str(next(verdaux_iter).name)
++ else:
++ verneed, vernaux = \
++ self._versioninfo['verneed'].get_version(index)
++ symbol_version['name'] = bytes2str(vernaux.name)
++ symbol_version['filename'] = bytes2str(verneed.name)
++
++ symbol_version['index'] = index
++ return symbol_version
++
+ def _section_from_spec(self, spec):
+ """ Retrieve a section given a "spec" (either number or name).
+ Return None if no such section exists in the file.
+@@ -802,6 +1042,9 @@
+ optparser.add_option('-p', '--string-dump',
+ action='store', dest='show_string_dump', metavar='<number|name>',
+ help='Dump the contents of section <number|name> as strings')
++ optparser.add_option('-V', '--version-info',
++ action='store_true', dest='show_version_info',
++ help='Display the version sections (if present)')
+ optparser.add_option('--debug-dump',
+ action='store', dest='debug_dump_what', metavar='<what>',
+ help=(
+@@ -838,6 +1081,8 @@
+ readelf.display_symbol_tables()
+ if options.show_relocs:
+ readelf.display_relocations()
++ if options.show_version_info:
++ readelf.display_version_info()
+ if options.show_hex_dump:
+ readelf.display_hex_dump(options.show_hex_dump)
+ if options.show_string_dump:
+diff -r 249a5ca85159 setup.py
+--- a/setup.py Wed Apr 17 05:57:58 2013 -0700
++++ b/setup.py Mon Jun 03 17:52:42 2013 +0200
+@@ -44,7 +44,7 @@
+ 'elftools.construct', 'elftools.construct.lib',
+ ],
+
+- scripts=['scripts/readelf.py'],
++ scripts=['scripts/readelf.py']
+ )
+
+
+diff -r 249a5ca85159 test/run_readelf_tests.py
+--- a/test/run_readelf_tests.py Wed Apr 17 05:57:58 2013 -0700
++++ b/test/run_readelf_tests.py Mon Jun 03 17:52:42 2013 +0200
+@@ -50,7 +50,7 @@
+ success = True
+ testlog.info("Test file '%s'" % filename)
+ for option in [
+- '-e', '-d', '-s', '-r', '-x.text', '-p.shstrtab',
++ '-e', '-d', '-s', '-r', '-x.text', '-p.shstrtab', '-V',
+ '--debug-dump=info', '--debug-dump=decodedline',
+ '--debug-dump=frames', '--debug-dump=frames-interp']:
+ if verbose: testlog.info("..option='%s'" % option)
+@@ -90,9 +90,9 @@
+ Note: this function contains some rather horrible hacks to ignore
+ differences which are not important for the verification of pyelftools.
+ This is due to some intricacies of binutils's readelf which pyelftools
+- doesn't currently implement, or silly inconsistencies in the output of
+- readelf, which I was reluctant to replicate.
+- Read the documentation for more details.
++ doesn't currently implement, features that binutils doesn't support,
++ or silly inconsistencies in the output of readelf, which I was reluctant
++ to replicate. Read the documentation for more details.
+ """
+ def prepare_lines(s):
+ return [line for line in s.lower().splitlines() if line.strip() != '']
+@@ -146,6 +146,9 @@
+ elif 'os/abi' in lines1[i]:
+ if 'unix - gnu' in lines1[i] and 'unix - linux' in lines2[i]:
+ ok = True
++ elif ( 'unknown at value' in lines1[i] and
++ 'dw_at_apple' in lines2[i]):
++ ok = True
+ else:
+ for s in ('t (tls)', 'l (large)'):
+ if s in lines1[i] or s in lines2[i]:
+@@ -183,7 +186,7 @@
+ if len(args) > 0:
+ filenames = args
+ else:
+- filenames = list(discover_testfiles('test/testfiles'))
++ filenames = list(discover_testfiles('test/testfiles_for_readelf'))
+
+ success = True
+ for filename in filenames:
+diff -r 249a5ca85159 test/test_arm_support.py
+--- a/test/test_arm_support.py Wed Apr 17 05:57:58 2013 -0700
++++ b/test/test_arm_support.py Mon Jun 03 17:52:42 2013 +0200
+@@ -15,7 +15,7 @@
+
+ class TestARMSupport(unittest.TestCase):
+ def test_hello(self):
+- with open(os.path.join('test', 'testfiles',
++ with open(os.path.join('test', 'testfiles_for_unittests',
+ 'simple_gcc.elf.arm'), 'rb') as f:
+ elf = ELFFile(f)
+ self.assertEqual(elf.get_machine_arch(), 'ARM')
+diff -r 249a5ca85159 test/test_gnuversions.py
+--- /dev/null Thu Jan 01 00:00:00 1970 +0000
++++ b/test/test_gnuversions.py Mon Jun 03 17:52:42 2013 +0200
+@@ -0,0 +1,160 @@
++#------------------------------------------------------------------------------
++# elftools tests
++#
++# Yann Rouillard (yann at pleiades.fr.eu.org)
++# This code is in the public domain
++#------------------------------------------------------------------------------
++try:
++ import unittest2 as unittest
++except ImportError:
++ import unittest
++import os
++
++from utils import setup_syspath
++setup_syspath()
++from elftools.elf.elffile import ELFFile
++from elftools.elf.constants import VER_FLAGS
++from elftools.elf.gnuversions import (
++ GNUVerNeedSection, GNUVerDefSection,
++ GNUVerSymSection)
++
++
++class TestSymbolVersioning(unittest.TestCase):
++
++ versym_reference_data = [
++ {'name': b'', 'ndx': 'VER_NDX_LOCAL'},
++ {'name': b'', 'ndx': 'VER_NDX_LOCAL'},
++ {'name': b'_ITM_deregisterTMCloneTable', 'ndx': 'VER_NDX_LOCAL'},
++ {'name': b'puts', 'ndx': 5},
++ {'name': b'strlcat', 'ndx': 'VER_NDX_LOCAL'},
++ {'name': b'__stack_chk_fail', 'ndx': 6},
++ {'name': b'__gmon_start__', 'ndx': 'VER_NDX_LOCAL'},
++ {'name': b'gzoffset', 'ndx': 7},
++ {'name': b'_Jv_RegisterClasses', 'ndx': 'VER_NDX_LOCAL'},
++ {'name': b'_ITM_registerTMCloneTable', 'ndx': 'VER_NDX_LOCAL'},
++ {'name': b'__cxa_finalize', 'ndx': 5},
++ {'name': b'_edata', 'ndx': 'VER_NDX_GLOBAL'},
++ {'name': b'VER_1.0', 'ndx': 2},
++ {'name': b'function1_ver1_1', 'ndx': 'VER_NDX_GLOBAL'},
++ {'name': b'_end', 'ndx': 'VER_NDX_GLOBAL'},
++ {'name': b'function1', 'ndx': 4 | 0x8000},
++ {'name': b'__bss_start', 'ndx': 'VER_NDX_GLOBAL'},
++ {'name': b'function1', 'ndx': 2},
++ {'name': b'VER_1.1', 'ndx': 3},
++ {'name': b'_init', 'ndx': 'VER_NDX_GLOBAL'},
++ {'name': b'function1_ver1_0', 'ndx': 'VER_NDX_GLOBAL'},
++ {'name': b'_fini', 'ndx': 'VER_NDX_GLOBAL'},
++ {'name': b'VER_1.2', 'ndx': 4},
++ {'name': b'function2', 'ndx': 3},
++ ]
++
++ def test_versym_section(self):
++
++ reference_data = TestSymbolVersioning.versym_reference_data
++
++ with open(os.path.join('test', 'testfiles_for_unittests',
++ 'lib_versioned64.so.1.elf'), 'rb') as f:
++ elf = ELFFile(f)
++ versym_section = None
++ for section in elf.iter_sections():
++ if isinstance(section, GNUVerSymSection):
++ versym_section = section
++ break
++
++ self.assertIsNotNone(versym_section)
++
++ for versym, ref_versym in zip(section.iter_symbols(),
++ reference_data):
++ self.assertEqual(versym.name, ref_versym['name'])
++ self.assertEqual(versym['ndx'], ref_versym['ndx'])
++
++ verneed_reference_data = [
++ {'name': b'libz.so.1', 'vn_version': 1, 'vn_cnt': 1,
++ 'vernaux': [
++ {'name': b'ZLIB_1.2.3.5', 'vna_flags': 0, 'vna_other': 7}]},
++ {'name': b'libc.so.6', 'vn_version': 1, 'vn_cnt': 2,
++ 'vernaux': [
++ {'name': b'GLIBC_2.4', 'vna_flags': 0, 'vna_other': 6},
++ {'name': b'GLIBC_2.2.5', 'vna_flags': 0, 'vna_other': 5}]},
++ ]
++
++ def test_verneed_section(self):
++
++ reference_data = TestSymbolVersioning.verneed_reference_data
++
++ with open(os.path.join('test', 'testfiles_for_unittests',
++ 'lib_versioned64.so.1.elf'), 'rb') as f:
++ elf = ELFFile(f)
++ verneed_section = None
++ for section in elf.iter_sections():
++ if isinstance(section, GNUVerNeedSection):
++ verneed_section = section
++ break
++
++ self.assertIsNotNone(verneed_section)
++
++ for (verneed, vernaux_iter), ref_verneed in zip(
++ section.iter_versions(), reference_data):
++
++ self.assertEqual(verneed.name, ref_verneed['name'])
++ self.assertEqual(verneed['vn_cnt'], ref_verneed['vn_cnt'])
++ self.assertEqual(verneed['vn_version'],
++ ref_verneed['vn_version'])
++
++ for vernaux, ref_vernaux in zip(
++ vernaux_iter, ref_verneed['vernaux']):
++
++ self.assertEqual(vernaux.name, ref_vernaux['name'])
++ self.assertEqual(vernaux['vna_flags'],
++ ref_vernaux['vna_flags'])
++ self.assertEqual(vernaux['vna_other'],
++ ref_vernaux['vna_other'])
++
++ verdef_reference_data = [
++ {'vd_ndx': 1, 'vd_version': 1, 'vd_flags': VER_FLAGS.VER_FLG_BASE,
++ 'vd_cnt': 1,
++ 'verdaux': [
++ {'name': b'lib_versioned.so.1'}]},
++ {'vd_ndx': 2, 'vd_version': 1, 'vd_flags': 0, 'vd_cnt': 1,
++ 'verdaux': [
++ {'name': b'VER_1.0'}]},
++ {'vd_ndx': 3, 'vd_version': 1, 'vd_flags': 0, 'vd_cnt': 2,
++ 'verdaux': [
++ {'name': b'VER_1.1'},
++ {'name': b'VER_1.0'}]},
++ {'vd_ndx': 4, 'vd_version': 1, 'vd_flags': 0, 'vd_cnt': 2,
++ 'verdaux': [
++ {'name': b'VER_1.2'},
++ {'name': b'VER_1.1'}]},
++ ]
++
++ def test_verdef_section(self):
++
++ reference_data = TestSymbolVersioning.verdef_reference_data
++
++ with open(os.path.join('test', 'testfiles_for_unittests',
++ 'lib_versioned64.so.1.elf'), 'rb') as f:
++ elf = ELFFile(f)
++ verneed_section = None
++ for section in elf.iter_sections():
++ if isinstance(section, GNUVerDefSection):
++ verdef_section = section
++ break
++
++ self.assertIsNotNone(verdef_section)
++
++ for (verdef, verdaux_iter), ref_verdef in zip(
++ section.iter_versions(), reference_data):
++
++ self.assertEqual(verdef['vd_ndx'], ref_verdef['vd_ndx'])
++ self.assertEqual(verdef['vd_version'],
++ ref_verdef['vd_version'])
++ self.assertEqual(verdef['vd_flags'], ref_verdef['vd_flags'])
++ self.assertEqual(verdef['vd_cnt'], ref_verdef['vd_cnt'])
++
++ for verdaux, ref_verdaux in zip(
++ verdaux_iter, ref_verdef['verdaux']):
++ self.assertEqual(verdaux.name, ref_verdaux['name'])
++
++if __name__ == '__main__':
++ unittest.main()
+diff -r 249a5ca85159 test/test_solaris_support.py
+--- /dev/null Thu Jan 01 00:00:00 1970 +0000
++++ b/test/test_solaris_support.py Mon Jun 03 17:52:42 2013 +0200
+@@ -0,0 +1,56 @@
++#-------------------------------------------------------------------------------
++# elftools tests
++#
++# Yann Rouillard (yann at pleiades.fr.eu.org)
++# This code is in the public domain
++#-------------------------------------------------------------------------------
++try:
++ import unittest2 as unittest
++except ImportError:
++ import unittest
++import os
++
++from utils import setup_syspath; setup_syspath()
++from elftools.elf.elffile import ELFFile
++from elftools.elf.constants import SUNW_SYMINFO_FLAGS
++
++
++class TestSolarisSupport(unittest.TestCase):
++
++ def _test_SUNW_syminfo_section_generic(self, testfile):
++ with open(os.path.join('test', 'testfiles_for_unittests',
++ testfile), 'rb') as f:
++ elf = ELFFile(f)
++ syminfo_section = elf.get_section_by_name(b'.SUNW_syminfo')
++ self.assertIsNotNone(syminfo_section)
++
++ # The test files were compiled against libc.so.1 with
++ # direct binding, hence the libc symbols used
++ # (exit, atexit and _exit) have the direct binding flags
++ # in the syminfo table.
++ # We check that this is properly detected.
++ exit_symbols = [s for s in syminfo_section.iter_symbols()
++ if b'exit' in s.name]
++ self.assertNotEqual(len(exit_symbols), 0)
++
++ for symbol in exit_symbols:
++ # libc.so.1 has the index 0 in the dynamic table
++ self.assertEqual(symbol['si_boundto'], 0)
++ self.assertEqual(symbol['si_flags'],
++ SUNW_SYMINFO_FLAGS.SYMINFO_FLG_DIRECT |
++ SUNW_SYMINFO_FLAGS.SYMINFO_FLG_DIRECTBIND)
++
++ def test_SUNW_syminfo_section_x86(self):
++ self._test_SUNW_syminfo_section_generic('exe_solaris32_cc.elf')
++
++ def test_SUNW_syminfo_section_x64(self):
++ self._test_SUNW_syminfo_section_generic('exe_solaris64_cc.elf')
++
++ def test_SUNW_syminfo_section_sparc32(self):
++ self._test_SUNW_syminfo_section_generic('exe_solaris32_cc.elf.sparc')
++
++ def test_SUNW_syminfo_section_sparc64(self):
++ self._test_SUNW_syminfo_section_generic('exe_solaris64_cc.elf.sparc')
++
++if __name__ == '__main__':
++ unittest.main()
+diff -r 249a5ca85159 test/testfiles/exe_simple32.elf
+Binary file test/testfiles/exe_simple32.elf has changed
+diff -r 249a5ca85159 test/testfiles/exe_simple64.elf
+Binary file test/testfiles/exe_simple64.elf has changed
+diff -r 249a5ca85159 test/testfiles/exe_stripped64.elf
+Binary file test/testfiles/exe_stripped64.elf has changed
+diff -r 249a5ca85159 test/testfiles/libelf0_8_13_32bit.so.elf
+Binary file test/testfiles/libelf0_8_13_32bit.so.elf has changed
+diff -r 249a5ca85159 test/testfiles/obj_simple32.o.elf
+Binary file test/testfiles/obj_simple32.o.elf has changed
+diff -r 249a5ca85159 test/testfiles/penalty_32_gcc.o.elf
+Binary file test/testfiles/penalty_32_gcc.o.elf has changed
+diff -r 249a5ca85159 test/testfiles/penalty_64_clang.o.elf
+Binary file test/testfiles/penalty_64_clang.o.elf has changed
+diff -r 249a5ca85159 test/testfiles/penalty_64_gcc.o.elf
+Binary file test/testfiles/penalty_64_gcc.o.elf has changed
+diff -r 249a5ca85159 test/testfiles/simple_gcc.elf.arm
+Binary file test/testfiles/simple_gcc.elf.arm has changed
+diff -r 249a5ca85159 test/testfiles/update32.o.elf
+Binary file test/testfiles/update32.o.elf has changed
+diff -r 249a5ca85159 test/testfiles_for_readelf/clang33-simple.o
+Binary file test/testfiles_for_readelf/clang33-simple.o has changed
+diff -r 249a5ca85159 test/testfiles_for_readelf/exe_simple32.elf
+Binary file test/testfiles_for_readelf/exe_simple32.elf has changed
+diff -r 249a5ca85159 test/testfiles_for_readelf/exe_simple64.elf
+Binary file test/testfiles_for_readelf/exe_simple64.elf has changed
+diff -r 249a5ca85159 test/testfiles_for_readelf/exe_stripped64.elf
+Binary file test/testfiles_for_readelf/exe_stripped64.elf has changed
+diff -r 249a5ca85159 test/testfiles_for_readelf/gcc48-simple.o
+Binary file test/testfiles_for_readelf/gcc48-simple.o has changed
+diff -r 249a5ca85159 test/testfiles_for_readelf/gcc48-simple.src.c
+--- /dev/null Thu Jan 01 00:00:00 1970 +0000
++++ b/test/testfiles_for_readelf/gcc48-simple.src.c Mon Jun 03 17:52:42 2013 +0200
+@@ -0,0 +1,19 @@
++/* Generated by compiling with gcc 4.8 as follows:
++**
++** gcc-4.8 -O0 -g -fno-dwarf2-cfi-asm -c dwarf4_simple.c -o gcc48-simple.
++**
++** Note: -fno-dwarf2-cfi-asm to tell gcc to generate .dwarf_frames as well
++** as the .eh_frames it generates by default.
++**
++*/
++
++extern int bar(int);
++extern int baz(int);
++
++int foo(int v) {
++ int x = bar(v);
++ int i;
++ for (i = 0; i < v; ++i)
++ x += bar(i) + bar(v) * baz(i);
++ return x;
++}
+diff -r 249a5ca85159 test/testfiles_for_readelf/libelf0_8_13_32bit.so.elf
+Binary file test/testfiles_for_readelf/libelf0_8_13_32bit.so.elf has changed
+diff -r 249a5ca85159 test/testfiles_for_readelf/obj_simple32.o.elf
+Binary file test/testfiles_for_readelf/obj_simple32.o.elf has changed
+diff -r 249a5ca85159 test/testfiles_for_readelf/penalty_32_gcc.o.elf
+Binary file test/testfiles_for_readelf/penalty_32_gcc.o.elf has changed
+diff -r 249a5ca85159 test/testfiles_for_readelf/penalty_64_clang.o.elf
+Binary file test/testfiles_for_readelf/penalty_64_clang.o.elf has changed
+diff -r 249a5ca85159 test/testfiles_for_readelf/penalty_64_gcc.o.elf
+Binary file test/testfiles_for_readelf/penalty_64_gcc.o.elf has changed
+diff -r 249a5ca85159 test/testfiles_for_readelf/update32.o.elf
+Binary file test/testfiles_for_readelf/update32.o.elf has changed
+diff -r 249a5ca85159 test/testfiles_for_unittests/exe_solaris32_cc.elf
+Binary file test/testfiles_for_unittests/exe_solaris32_cc.elf has changed
+diff -r 249a5ca85159 test/testfiles_for_unittests/exe_solaris32_cc.elf.sparc
+Binary file test/testfiles_for_unittests/exe_solaris32_cc.elf.sparc has changed
+diff -r 249a5ca85159 test/testfiles_for_unittests/exe_solaris64_cc.elf
+Binary file test/testfiles_for_unittests/exe_solaris64_cc.elf has changed
+diff -r 249a5ca85159 test/testfiles_for_unittests/exe_solaris64_cc.elf.sparc
+Binary file test/testfiles_for_unittests/exe_solaris64_cc.elf.sparc has changed
+diff -r 249a5ca85159 test/testfiles_for_unittests/lib_versioned64.so.1.elf
+Binary file test/testfiles_for_unittests/lib_versioned64.so.1.elf has changed
+diff -r 249a5ca85159 test/testfiles_for_unittests/simple_gcc.elf.arm
+Binary file test/testfiles_for_unittests/simple_gcc.elf.arm has changed
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
More information about the devel
mailing list