More changes to port to Python 3
authorEli Bendersky <eliben@gmail.com>
Fri, 27 Jan 2012 08:25:47 +0000 (10:25 +0200)
committerEli Bendersky <eliben@gmail.com>
Fri, 27 Jan 2012 08:25:47 +0000 (10:25 +0200)
All tox tests pass now!!

26 files changed:
elftools/common/py3compat.py
elftools/common/utils.py
elftools/dwarf/descriptions.py
elftools/dwarf/dwarf_expr.py
elftools/dwarf/lineprogram.py
elftools/dwarf/structs.py
elftools/elf/descriptions.py
elftools/elf/elffile.py
elftools/elf/relocation.py
elftools/elf/sections.py
examples/dwarf_die_tree.py
examples/dwarf_location_lists.py
examples/dwarf_range_lists.py
examples/elf_low_high_api.py
examples/elf_relocations.py
examples/elf_show_debug_sections.py
examples/examine_dwarf_info.py
scripts/readelf.py
test/run_all_unittests.py
test/test_callframe.py
test/test_dwarf_expr.py
test/test_dwarf_lineprogram.py
test/test_dwarf_structs.py
test/test_utils.py
test/utils.py
tox.ini

index bd08bd21c80f8f6baba04e55ca2ca2c98fa8f3e6..9b4529f38d45cc1928d3cd31d15eb1873f508993 100644 (file)
@@ -20,6 +20,14 @@ if PY3:
 
     _iterkeys = "keys"
     _iteritems = "items"
+    _itervalues = "values"
+
+    def bytes2str(b): return b.decode('latin-1')
+    def str2bytes(s): return s.encode('latin-1')
+    def int2byte(i):return bytes((i,))
+    def byte2int(b): return b
+
+    ifilter = filter
 else:
     import cStringIO
     StringIO = BytesIO = cStringIO.StringIO
@@ -28,12 +36,24 @@ else:
 
     _iterkeys = "iterkeys"
     _iteritems = "iteritems"
+    _itervalues = "itervalues"
+
+    def bytes2str(b): return b
+    def str2bytes(s): return s
+    int2byte = chr
+    byte2int = ord
+
+    from itertools import ifilter
 
 
 def iterkeys(d):
     """Return an iterator over the keys of a dictionary."""
     return getattr(d, _iterkeys)()
 
+def itervalues(d):
+    """Return an iterator over the values of a dictionary."""
+    return getattr(d, _itervalues)()
+
 def iteritems(d):
     """Return an iterator over the items of a dictionary."""
     return getattr(d, _iteritems)()
index e0a4cfef6e8d8a9298ccb7dfbd669adf867d7bcd..2daed04c51cde36a9f0185312d75c5b602f72b4c 100644 (file)
@@ -8,14 +8,15 @@
 #-------------------------------------------------------------------------------
 from contextlib import contextmanager
 from .exceptions import ELFParseError, ELFError, DWARFError
+from .py3compat import int2byte
 from ..construct import ConstructError
 
 
 def bytelist2string(bytelist):
-    """ Convert a list of byte values (e.g. [0x10 0x20 0x00]) to a string
-        (e.g. '\x10\x20\x00').
+    """ Convert a list of byte values (e.g. [0x10 0x20 0x00]) to a bytes object
+        (e.g. b'\x10\x20\x00').
     """
-    return ''.join(chr(b) for b in bytelist)
+    return b''.join(int2byte(b) for b in bytelist)
 
 
 def struct_parse(struct, stream, stream_pos=None):
@@ -48,7 +49,7 @@ def parse_cstring_from_stream(stream, stream_pos=None):
     found = False
     while True:
         chunk = stream.read(CHUNKSIZE)
-        end_index = chunk.find('\x00')
+        end_index = chunk.find(b'\x00')
         if end_index >= 0:
             chunks.append(chunk[:end_index])
             found = True
@@ -57,7 +58,7 @@ def parse_cstring_from_stream(stream, stream_pos=None):
             chunks.append(chunk)
         if len(chunk) < CHUNKSIZE:
             break
-    return ''.join(chunks) if found else None
+    return b''.join(chunks) if found else None
 
 
 def elf_assert(cond, msg=''):
index c467c6af85735d12530ea97a23284bdb3b0498aa..721c97a51723c1fe4728b78d070fab48cfffafd5 100644 (file)
@@ -12,6 +12,7 @@ from .constants import *
 from .dwarf_expr import GenericExprVisitor
 from .die import DIE
 from ..common.utils import preserve_stream_pos, dwarf_assert
+from ..common.py3compat import bytes2str
 from .callframe import instruction_name, CIE, FDE
 
 
@@ -184,7 +185,11 @@ def _describe_attr_split_64bit(attr, die, section_offset):
     return '0x%x 0x%x' % (low_word, high_word)
 
 def _describe_attr_strp(attr, die, section_offset):
-    return '(indirect string, offset: 0x%x): %s' % (attr.raw_value, attr.value)
+    return '(indirect string, offset: 0x%x): %s' % (
+        attr.raw_value, bytes2str(attr.value))
+
+def _describe_attr_string(attr, die, section_offset):
+    return bytes2str(attr.value)
 
 def _describe_attr_debool(attr, die, section_offset):
     """ To be consistent with readelf, generate 1 for True flags, 0 for False
@@ -216,7 +221,7 @@ _ATTR_DESCRIPTION_MAP = defaultdict(
     DW_FORM_data2=_describe_attr_value_passthrough,
     DW_FORM_sdata=_describe_attr_value_passthrough,
     DW_FORM_udata=_describe_attr_value_passthrough,
-    DW_FORM_string=_describe_attr_value_passthrough,
+    DW_FORM_string=_describe_attr_string,
     DW_FORM_strp=_describe_attr_strp,
     DW_FORM_block1=_describe_attr_block,
     DW_FORM_block2=_describe_attr_block,
index 267c1c7fd9b687bd876ca31ed218c57096de7336..270a78165b476b8bd67c729740fd553a0985ec93 100644 (file)
@@ -6,7 +6,7 @@
 # Eli Bendersky (eliben@gmail.com)
 # This code is in the public domain
 #-------------------------------------------------------------------------------
-from ..common.py3compat import StringIO, iteritems
+from ..common.py3compat import BytesIO, iteritems
 from ..common.utils import struct_parse, bytelist2string
 
 
@@ -116,7 +116,7 @@ class GenericExprVisitor(object):
         """ Process (visit) a DWARF expression. expr should be a list of
             (integer) byte values.
         """
-        self.stream = StringIO(bytelist2string(expr))
+        self.stream = BytesIO(bytelist2string(expr))
 
         while True:
             # Get the next opcode from the stream. If nothing is left in the
index 4d9c7b0e57bc92d2a9f7ac91412fb6bf9b6a02bb..ee5193ee8685ea4c4127f0d0c4155cf080837bdb 100644 (file)
@@ -152,7 +152,7 @@ class LineProgram(object):
             if opcode >= self.header['opcode_base']:
                 # Special opcode (follow the recipe in 6.2.5.1)
                 adjusted_opcode = opcode - self['opcode_base']
-                address_addend = ((adjusted_opcode / self['line_range']) *
+                address_addend = ((adjusted_opcode // self['line_range']) *
                                   self['minimum_instruction_length'])
                 state.address += address_addend
                 line_addend = (self['line_base'] + 
@@ -221,7 +221,7 @@ class LineProgram(object):
                     add_entry_old_state(opcode, [operand])
                 elif opcode == DW_LNS_const_add_pc:
                     adjusted_opcode = 255 - self['opcode_base']
-                    address_addend = ((adjusted_opcode / self['line_range']) *
+                    address_addend = ((adjusted_opcode // self['line_range']) *
                                       self['minimum_instruction_length'])
                     state.address += address_addend
                     add_entry_old_state(opcode, [address_addend])
index 10154ae2471fcb5f397b99f36eece643a803d52f..cfb2515a0ab97fe652b4ac20d0f66aeb64982213 100644 (file)
@@ -218,7 +218,7 @@ class DWARFStructs(object):
             Array(lambda ctx: ctx['opcode_base'] - 1, 
                   self.Dwarf_uint8('standard_opcode_lengths')),
             RepeatUntilExcluding(
-                lambda obj, ctx: obj == '',
+                lambda obj, ctx: obj == b'',
                 CString('include_directory')),
             RepeatUntilExcluding(
                 lambda obj, ctx: len(obj.name) == 0,
index fa630de90420e0dd649931ae13577e69efd4f65d..2cde281b21e8b9fab5c641710632d500c65d010b 100644 (file)
@@ -8,6 +8,7 @@
 #-------------------------------------------------------------------------------
 from .enums import ENUM_E_VERSION, ENUM_RELOC_TYPE_i386, ENUM_RELOC_TYPE_x64
 from .constants import P_FLAGS, SH_FLAGS
+from ..common.py3compat import iteritems
 
 
 def describe_ei_class(x):
@@ -231,9 +232,9 @@ _DESCR_ST_SHNDX = dict(
 )
 
 _DESCR_RELOC_TYPE_i386 = dict(
-        (v, k) for k, v in ENUM_RELOC_TYPE_i386.iteritems())
+        (v, k) for k, v in iteritems(ENUM_RELOC_TYPE_i386))
 
 _DESCR_RELOC_TYPE_x64 = dict(
-        (v, k) for k, v in ENUM_RELOC_TYPE_x64.iteritems())
+        (v, k) for k, v in iteritems(ENUM_RELOC_TYPE_x64))
 
 
index 23349b433e80f52826b49d28744ef03187f960a7..bda6cae1bf83268397f8e8911a77c91f01b0e3fa 100644 (file)
@@ -6,7 +6,7 @@
 # Eli Bendersky (eliben@gmail.com)
 # This code is in the public domain
 #-------------------------------------------------------------------------------
-from ..common.py3compat import StringIO
+from ..common.py3compat import BytesIO
 from ..common.exceptions import ELFError
 from ..common.utils import struct_parse, elf_assert
 from ..construct import ConstructError
@@ -109,7 +109,7 @@ class ELFFile(object):
             We assume that if it has the debug_info section, it has all theother
             required sections as well.
         """
-        return bool(self.get_section_by_name('.debug_info'))
+        return bool(self.get_section_by_name(b'.debug_info'))
 
     def get_dwarf_info(self, relocate_dwarf_sections=True):
         """ Return a DWARFInfo object representing the debugging information in
@@ -123,9 +123,9 @@ class ELFFile(object):
         # Sections that aren't found will be passed as None to DWARFInfo.
         #
         debug_sections = {}
-        for secname in ('.debug_info', '.debug_abbrev', '.debug_str', 
-                        '.debug_line', '.debug_frame', '.debug_loc',
-                        '.debug_ranges'):
+        for secname in (b'.debug_info', b'.debug_abbrev', b'.debug_str', 
+                        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
@@ -139,13 +139,13 @@ class ELFFile(object):
                     little_endian=self.little_endian,
                     default_address_size=self.elfclass / 8,
                     machine_arch=self.get_machine_arch()),
-                debug_info_sec=debug_sections['.debug_info'],
-                debug_abbrev_sec=debug_sections['.debug_abbrev'],
-                debug_frame_sec=debug_sections['.debug_frame'],
-                debug_str_sec=debug_sections['.debug_str'],
-                debug_loc_sec=debug_sections['.debug_loc'],
-                debug_ranges_sec=debug_sections['.debug_ranges'],
-                debug_line_sec=debug_sections['.debug_line'])
+                debug_info_sec=debug_sections[b'.debug_info'],
+                debug_abbrev_sec=debug_sections[b'.debug_abbrev'],
+                debug_frame_sec=debug_sections[b'.debug_frame'],
+                debug_str_sec=debug_sections[b'.debug_str'],
+                debug_loc_sec=debug_sections[b'.debug_loc'],
+                debug_ranges_sec=debug_sections[b'.debug_ranges'],
+                debug_line_sec=debug_sections[b'.debug_line'])
 
     def get_machine_arch(self):
         """ Return the machine architecture, as detected from the ELF header.
@@ -283,9 +283,7 @@ class ELFFile(object):
         """
         self.stream.seek(section['sh_offset'])
         # The section data is read into a new stream, for processing
-        section_stream = StringIO()
-        # Using .write instead of initializing StringIO with the string because
-        # such a StringIO from cStringIO is read-only.
+        section_stream = BytesIO()
         section_stream.write(self.stream.read(section['sh_size']))
 
         if relocate_dwarf_sections:
index acb2da2d2536003150bac474dd190de87e238e8a..5ff853beda9376dfa081f3477b6cdadaf3b3b11c 100644 (file)
@@ -102,8 +102,8 @@ class RelocationHandler(object):
             found.
         """
         reloc_section_names = (
-                '.rel' + section.name,
-                '.rela' + section.name)
+                b'.rel' + section.name,
+                b'.rela' + section.name)
         # Find the relocation section aimed at this one. Currently assume
         # that either .rel or .rela section exists for this section, but
         # not both.
index 11aa170eab2c99998dc77cb2d6ca12c19f83bb61..518c857aa92c28bdd5fdc7aab457426a5fc8efaf 100644 (file)
@@ -7,7 +7,7 @@
 # This code is in the public domain
 #-------------------------------------------------------------------------------
 from ..construct import CString
-from ..common.utils import struct_parse, elf_assert
+from ..common.utils import struct_parse, elf_assert, parse_cstring_from_stream
 
 
 class Section(object):
@@ -63,10 +63,8 @@ class StringTableSection(Section):
         """ Get the string stored at the given offset in this string table.
         """
         table_offset = self['sh_offset']
-        return struct_parse(
-            CString(''),
-            self.stream,
-            stream_pos=table_offset + offset)
+        s = parse_cstring_from_stream(self.stream, table_offset + offset)
+        return s
 
 
 class SymbolTableSection(Section):
index 9650f309d68e5fccc77e0b05d003851ab97e17d2..7eb07ff3a3b687436cbbeb3a7deaefa96405e6ca 100644 (file)
@@ -17,6 +17,7 @@ try:
 except ImportError:
     sys.path.extend(['.', '..'])
 
+from elftools.common.py3compat import bytes2str
 from elftools.elf.elffile import ELFFile
 
 
@@ -54,7 +55,7 @@ def process_file(filename):
             # is done transparently by the library, and such a value will be
             # simply given as a string.
             name_attr = top_DIE.attributes['DW_AT_name']
-            print('    name=%s' % name_attr.value)
+            print('    name=%s' % bytes2str(name_attr.value))
 
             # Display DIEs recursively starting with top_DIE
             die_info_rec(top_DIE)
index 3ac989c2743fa2576f508ededa0a5308eb0cfa11..62896189c1e717f7c3fa645e04dc50f175fe2553 100644 (file)
@@ -17,6 +17,7 @@ try:
 except ImportError:
     sys.path.extend(['.', '..'])
 
+from elftools.common.py3compat import itervalues
 from elftools.elf.elffile import ELFFile
 from elftools.dwarf.descriptions import (
     describe_DWARF_expr, set_global_machine_arch)
@@ -58,7 +59,7 @@ def process_file(filename):
                 # Go over all attributes of the DIE. Each attribute is an
                 # AttributeValue object (from elftools.dwarf.die), which we
                 # can examine.
-                for attr in DIE.attributes.itervalues():
+                for attr in itervalues(DIE.attributes):
                     if attribute_has_location_list(attr):
                         # This is a location list. Its value is an offset into
                         # the .debug_loc section, so we can use the location
@@ -71,6 +72,7 @@ def process_file(filename):
                             attr.name,
                             show_loclist(loclist, dwarfinfo, indent='      ')))
 
+
 def show_loclist(loclist, dwarfinfo, indent):
     """ Display a location list nicely, decoding the DWARF expressions
         contained within.
index 48a0cbbaa2111280d2563a10b620dea157f3ef47..c310e584f125d50c392d6a973bc8f276a59e3865 100644 (file)
@@ -17,6 +17,7 @@ try:
 except ImportError:
     sys.path.extend(['.', '..'])
 
+from elftools.common.py3compat import itervalues
 from elftools.elf.elffile import ELFFile
 from elftools.dwarf.descriptions import (
     describe_DWARF_expr, set_global_machine_arch)
@@ -54,7 +55,7 @@ def process_file(filename):
                 # Go over all attributes of the DIE. Each attribute is an
                 # AttributeValue object (from elftools.dwarf.die), which we
                 # can examine.
-                for attr in DIE.attributes.itervalues():
+                for attr in itervalues(DIE.attributes):
                     if attribute_has_range_list(attr):
                         # This is a range list. Its value is an offset into
                         # the .debug_ranges section, so we can use the range
index a5600c1aae05f93bb3d03547727e3450cb50b4a1..05d75642ac88fbc51600909441c012a86537ec0b 100644 (file)
@@ -18,6 +18,7 @@ try:
 except ImportError:
     sys.path.extend(['.', '..'])
 
+from elftools.common.py3compat import bytes2str
 from elftools.elf.elffile import ELFFile
 from elftools.elf.sections import SymbolTableSection
 
@@ -63,8 +64,10 @@ def section_info_highlevel(stream):
     elffile = ELFFile(stream)
 
     # Just use the public methods of ELFFile to get what we need
+    # Note that section names, like everything read from the file, are bytes
+    # objects.
     print('  %s sections' % elffile.num_sections())
-    section = elffile.get_section_by_name('.symtab')
+    section = elffile.get_section_by_name(b'.symtab')
 
     if not section:
         print('  No symbol table found. Perhaps this ELF has been stripped?')
@@ -72,8 +75,10 @@ def section_info_highlevel(stream):
 
     # A section type is in its header, but the name was decoded and placed in
     # a public attribute.
+    # bytes2str is used to print the name of the section for consistency of
+    # output between Python 2 and 3. The section name is a bytes object.
     print('  Section name: %s, type: %s' %(
-        section.name, section['sh_type']))
+        bytes2str(section.name), section['sh_type']))
 
     # But there's more... If this section is a symbol table section (which is
     # the case in the sample ELF file that comes with the examples), we can
@@ -82,7 +87,7 @@ def section_info_highlevel(stream):
         num_symbols = section.num_symbols()
         print("  It's a symbol section with %s symbols" % num_symbols)
         print("  The name of the last symbol in the section is: %s" % (
-            section.get_symbol(num_symbols - 1).name))
+            bytes2str(section.get_symbol(num_symbols - 1).name)))
 
 
 if __name__ == '__main__':
index 181759506d560c0645f6ee0a018f56ba686e4518..fd65541954c70119a2621a11f3bf244d61ea5e1b 100644 (file)
@@ -17,6 +17,7 @@ try:
 except ImportError:
     sys.path.extend(['.', '..'])
 
+from elftools.common.py3compat import bytes2str
 from elftools.elf.elffile import ELFFile
 from elftools.elf.relocation import RelocationSection
 
@@ -28,14 +29,15 @@ def process_file(filename):
 
         # Read the .rela.dyn section from the file, by explicitly asking
         # ELFFile for this section
-        reladyn_name = '.rela.dyn'
+        # Recall that section names are bytes objects
+        reladyn_name = b'.rela.dyn'
         reladyn = elffile.get_section_by_name(reladyn_name)
 
         if not isinstance(reladyn, RelocationSection):
-            print('  The file has no %s section' % reladyn_name)
+            print('  The file has no %s section' % bytes2str(reladyn_name))
 
         print('  %s section with %s relocations' % (
-            reladyn_name, reladyn.num_relocations()))
+            bytes2str(reladyn_name), reladyn.num_relocations()))
 
         for reloc in reladyn.iter_relocations():
             print('    Relocation (%s)' % 'RELA' if reloc.is_RELA() else 'REL')
index a7e0d227d55de72f6a9230c988c7611a5edfb0de..96e1dd9df88b87e160d31a3e857b5f507a45684d 100644 (file)
@@ -16,6 +16,7 @@ try:
 except ImportError:
     sys.path.extend(['.', '..'])
 
+from elftools.common.py3compat import bytes2str
 from elftools.elf.elffile import ELFFile
 
 
@@ -25,8 +26,9 @@ def process_file(filename):
         elffile = ELFFile(f)
 
         for section in elffile.iter_sections():
-            if section.name.startswith('.debug'):
-                print('  ' + section.name)
+            # Section names are bytes objects
+            if section.name.startswith(b'.debug'):
+                print('  ' + bytes2str(section.name))
 
 
 if __name__ == '__main__':
index 6be47b91c7cfd6f23ecc24746ce4073ce4a21f24..35ce35bbc40f4567c4f59de1fe4e8176c475ad90 100644 (file)
@@ -16,6 +16,7 @@ try:
 except ImportError:
     sys.path.extend(['.', '..'])
 
+from elftools.common.py3compat import bytes2str
 from elftools.elf.elffile import ELFFile
 
 
@@ -53,7 +54,7 @@ def process_file(filename):
             # is done transparently by the library, and such a value will be
             # simply given as a string.
             name_attr = top_DIE.attributes['DW_AT_name']
-            print('    name=%s' % name_attr.value)
+            print('    name=%s' % bytes2str(name_attr.value))
 
 if __name__ == '__main__':
     for filename in sys.argv[1:]:
index 6ecac7bd8a68f4db92cf5ac976ceeced8f70eda5..04c75bafca304474d5b6c671aa005e993d7e1e5f 100755 (executable)
@@ -9,7 +9,6 @@
 #-------------------------------------------------------------------------------
 import os, sys
 from optparse import OptionParser
-from itertools import ifilter
 import string
 
 # If elftools is not installed, maybe we're running from the root or scripts
@@ -21,6 +20,8 @@ except ImportError:
 
 from elftools import __version__
 from elftools.common.exceptions import ELFError
+from elftools.common.py3compat import (
+        ifilter, byte2int, bytes2str, itervalues, str2bytes)
 from elftools.elf.elffile import ELFFile
 from elftools.elf.segments import InterpSegment
 from elftools.elf.sections import SymbolTableSection
@@ -65,7 +66,7 @@ class ReadElf(object):
         """
         self._emitline('ELF Header:')
         self._emit('  Magic:   ')
-        self._emitline(' '.join('%2.2x' % ord(b) 
+        self._emitline(' '.join('%2.2x' % byte2int(b)
                                     for b in self.elffile.e_ident_raw))
         header = self.elffile.header
         e_ident = header['e_ident']
@@ -173,7 +174,7 @@ class ReadElf(object):
 
             if isinstance(segment, InterpSegment):
                 self._emitline('      [Requesting program interpreter: %s]' % 
-                    segment.get_interp_name())
+                    bytes2str(segment.get_interp_name()))
 
         # Sections to segments mapping
         #
@@ -190,7 +191,7 @@ class ReadElf(object):
             for section in self.elffile.iter_sections():
                 if (    not section.is_null() and 
                         segment.section_in_segment(section)):
-                    self._emit('%s ' % section.name)
+                    self._emit('%s ' % bytes2str(section.name))
 
             self._emitline('')
 
@@ -217,7 +218,7 @@ class ReadElf(object):
         #
         for nsec, section in enumerate(self.elffile.iter_sections()):
             self._emit('  [%2u] %-17.17s %-15.15s ' % (
-                nsec, section.name, describe_sh_type(section['sh_type'])))
+                nsec, bytes2str(section.name), describe_sh_type(section['sh_type'])))
 
             if self.elffile.elfclass == 32:
                 self._emitline('%s %s %s %s %3s %2s %3s %2s' % (
@@ -259,11 +260,11 @@ class ReadElf(object):
 
             if section['sh_entsize'] == 0:
                 self._emitline("\nSymbol table '%s' has a sh_entsize of zero!" % (
-                    section.name))
+                    bytes2str(section.name)))
                 continue
 
             self._emitline("\nSymbol table '%s' contains %s entries:" % (
-                section.name, section.num_symbols()))
+                bytes2str(section.name), section.num_symbols()))
 
             if self.elffile.elfclass == 32:
                 self._emitline('   Num:    Value  Size Type    Bind   Vis      Ndx Name')
@@ -280,7 +281,7 @@ class ReadElf(object):
                     describe_symbol_bind(symbol['st_info']['bind']),
                     describe_symbol_visibility(symbol['st_other']['visibility']),
                     describe_symbol_shndx(symbol['st_shndx']),
-                    symbol.name))
+                    bytes2str(symbol.name)))
         
     def display_relocations(self):
         """ Display the relocations contained in the file
@@ -292,7 +293,7 @@ class ReadElf(object):
 
             has_relocation_sections = True
             self._emitline("\nRelocation section '%s' at offset %s contains %s entries:" % (
-                section.name,
+                bytes2str(section.name),
                 self._format_hex(section['sh_offset']),
                 section.num_relocations()))
             if section.is_RELA():
@@ -330,7 +331,7 @@ class ReadElf(object):
                         symbol['st_value'],
                         fullhex=True, lead0x=False),
                     '  ' if self.elffile.elfclass == 32 else '',
-                    symbol_name))
+                    bytes2str(symbol_name)))
                 if section.is_RELA():
                     self._emit(' %s %x' % (
                         '+' if rel['r_addend'] >= 0 else '-',
@@ -350,7 +351,7 @@ class ReadElf(object):
                 section_spec))
             return
 
-        self._emitline("\nHex dump of section '%s':" % section.name)
+        self._emitline("\nHex dump of section '%s':" % bytes2str(section.name))
         self._note_relocs_for_section(section)
         addr = section['sh_addr']
         data = section.data()
@@ -364,18 +365,18 @@ class ReadElf(object):
             self._emit('  %s ' % self._format_hex(addr, fieldsize=8))
             for i in range(16):
                 if i < linebytes:
-                    self._emit('%2.2x' % ord(data[dataptr + i]))
+                    self._emit('%2.2x' % byte2int(data[dataptr + i]))
                 else:
                     self._emit('  ')
                 if i % 4 == 3:
                     self._emit(' ')
 
             for i in range(linebytes):
-                c = data[dataptr + i]
-                if c >= ' ' and ord(c) < 0x7f:
-                    self._emit(c)
+                c = data[dataptr + i : dataptr + i + 1]
+                if byte2int(c[0]) >= 32 and byte2int(c[0]) < 0x7f:
+                    self._emit(bytes2str(c))
                 else:
-                    self._emit('.')
+                    self._emit(bytes2str(b'.'))
 
             self._emitline()
             addr += linebytes
@@ -393,27 +394,27 @@ class ReadElf(object):
                 section_spec))
             return
 
-        printables = set(string.printable)
-        self._emitline("\nString dump of section '%s':" % section.name)
+        self._emitline("\nString dump of section '%s':" % bytes2str(section.name))
 
         found = False
         data = section.data()
         dataptr = 0
 
         while dataptr < len(data):
-            while dataptr < len(data) and data[dataptr] not in printables:
+            while ( dataptr < len(data) and 
+                    not (32 <= byte2int(data[dataptr]) <= 127)):
                 dataptr += 1
 
             if dataptr >= len(data):
                 break
 
             endptr = dataptr
-            while endptr < len(data) and data[endptr] != '\x00':
+            while endptr < len(data) and byte2int(data[endptr]) != 0:
                 endptr += 1
 
             found = True
             self._emitline('  [%6x]  %s' % (
-                dataptr, data[dataptr:endptr]))
+                dataptr, bytes2str(data[dataptr:endptr])))
 
             dataptr = endptr
 
@@ -479,7 +480,7 @@ class ReadElf(object):
                 return None
         except ValueError:
             # Not a number. Must be a name then
-            return self.elffile.get_section_by_name(spec)
+            return self.elffile.get_section_by_name(str2bytes(spec))
 
     def _note_relocs_for_section(self, section):
         """ If there are relocation sections pointing to the givne section,
@@ -540,7 +541,7 @@ class ReadElf(object):
                     die.abbrev_code,
                     die.tag))
                 
-                for attr in die.attributes.itervalues():
+                for attr in itervalues(die.attributes):
                     name = attr.name
                     # Unknown attribute values are passed-through as integers
                     if isinstance(name, int):
@@ -568,10 +569,10 @@ class ReadElf(object):
             cu_filename = ''
             if len(lineprogram['include_directory']) > 0:
                 cu_filename = '%s/%s' % (
-                    lineprogram['include_directory'][0],
-                    lineprogram['file_entry'][0].name)
+                    bytes2str(lineprogram['include_directory'][0]),
+                    bytes2str(lineprogram['file_entry'][0].name))
             else:
-                cu_filename = lineprogram['file_entry'][0].name
+                cu_filename = bytes2str(lineprogram['file_entry'][0].name)
 
             self._emitline('CU: %s:' % cu_filename)
             self._emitline('File name                            Line number    Starting address')
@@ -588,20 +589,20 @@ class ReadElf(object):
                         if file_entry.dir_index == 0:
                             # current directory
                             self._emitline('\n./%s:[++]' % (
-                                file_entry.name))
+                                bytes2str(file_entry.name)))
                         else:
                             self._emitline('\n%s/%s:' % (
-                                lineprogram['include_directory'][file_entry.dir_index - 1],
-                                file_entry.name))
+                                bytes2str(lineprogram['include_directory'][file_entry.dir_index - 1]),
+                                bytes2str(file_entry.name)))
                     elif entry.command == DW_LNE_define_file:
                         self._emitline('%s:' % (
-                            lineprogram['include_directory'][entry.args[0].dir_index]))
+                            bytes2str(lineprogram['include_directory'][entry.args[0].dir_index])))
                 elif not state.end_sequence:
                     # readelf doesn't print the state after end_sequence
                     # instructions. I think it's a bug but to be compatible
                     # I don't print them too.
                     self._emitline('%-35s  %11d  %18s' % (
-                        lineprogram['file_entry'][state.file - 1].name,
+                        bytes2str(lineprogram['file_entry'][state.file - 1].name),
                         state.line,
                         '0' if state.address == 0 else 
                                self._format_hex(state.address)))
@@ -621,7 +622,7 @@ class ReadElf(object):
                 self._emitline('\n%08x %08x %08x CIE' % (
                     entry.offset, entry['length'], entry['CIE_id']))
                 self._emitline('  Version:               %d' % entry['version'])
-                self._emitline('  Augmentation:          "%s"' % entry['augmentation'])
+                self._emitline('  Augmentation:          "%s"' % bytes2str(entry['augmentation']))
                 self._emitline('  Code alignment factor: %u' % entry['code_alignment_factor'])
                 self._emitline('  Data alignment factor: %d' % entry['data_alignment_factor'])
                 self._emitline('  Return address column: %d' % entry['return_address_register'])
@@ -652,7 +653,7 @@ class ReadElf(object):
                     entry.offset,
                     entry['length'],
                     entry['CIE_id'],
-                    entry['augmentation'],
+                    bytes2str(entry['augmentation']),
                     entry['code_alignment_factor'],
                     entry['data_alignment_factor'],
                     entry['return_address_register']))
index e1a62f2196135936a740b8f7915a90bb7e21a6bc..1130251a486936ece75f8a478b47086b61d11521 100755 (executable)
@@ -7,6 +7,8 @@
 # Eli Bendersky (eliben@gmail.com)
 # This code is in the public domain
 #-------------------------------------------------------------------------------
+from __future__ import print_function
+
 try:
     import unittest2 as unittest
 except ImportError:
@@ -18,6 +20,7 @@ if __name__ == '__main__':
         tests = unittest.TestLoader().discover('test', 'test*.py', 'test')
         unittest.TextTestRunner().run(tests)
     except ImportError as err:
-        print err
-        print '!! Please execute from the root directory of pyelftools'
+        print(err)
+        print('!! Please execute from the root directory of pyelftools')
+
 
index 3fe1b9a6b62c16b68775c1e5d1e893701eabfe3d..33fb1e74a79b86ca1ee7063ba25d6d1279eb3835 100644 (file)
@@ -3,9 +3,9 @@ try:
 except ImportError:
     import unittest
 import sys
-from cStringIO import StringIO
 
 sys.path.extend(['.', '..'])
+from elftools.common.py3compat import BytesIO
 from elftools.dwarf.callframe import (
     CallFrameInfo, CIE, FDE, instruction_name, CallFrameInstruction,
     RegisterRule)
@@ -22,42 +22,42 @@ class TestCallFrame(unittest.TestCase):
        
     def test_spec_sample_d6(self):
         # D.6 sample in DWARFv3
-        s = StringIO()
-        data = ('' +
+        s = BytesIO()
+        data = (b'' +
             # first comes the CIE
-            '\x20\x00\x00\x00' +        # length
-            '\xff\xff\xff\xff' +        # CIE_id
-            '\x03\x00\x04\x7c' +        # version, augmentation, caf, daf
-            '\x08' +                    # return address
-            '\x0c\x07\x00' +
-            '\x08\x00' +
-            '\x07\x01' +
-            '\x07\x02' +
-            '\x07\x03' +
-            '\x08\x04' +
-            '\x08\x05' +
-            '\x08\x06' +
-            '\x08\x07' +
-            '\x09\x08\x01' +
-            '\x00' +
+            b'\x20\x00\x00\x00' +        # length
+            b'\xff\xff\xff\xff' +        # CIE_id
+            b'\x03\x00\x04\x7c' +        # version, augmentation, caf, daf
+            b'\x08' +                    # return address
+            b'\x0c\x07\x00' +
+            b'\x08\x00' +
+            b'\x07\x01' +
+            b'\x07\x02' +
+            b'\x07\x03' +
+            b'\x08\x04' +
+            b'\x08\x05' +
+            b'\x08\x06' +
+            b'\x08\x07' +
+            b'\x09\x08\x01' +
+            b'\x00' +
             
             # then comes the FDE
-            '\x28\x00\x00\x00' +        # length
-            '\x00\x00\x00\x00' +        # CIE_pointer (to CIE at 0)
-            '\x44\x33\x22\x11' +        # initial_location
-            '\x54\x00\x00\x00' +        # address range
-            '\x41' +
-            '\x0e\x0c' + '\x41' +
-            '\x88\x01' + '\x41' +
-            '\x86\x02' + '\x41' +
-            '\x0d\x06' + '\x41' +
-            '\x84\x03' + '\x4b' +
-            '\xc4' + '\x41' +
-            '\xc6' +
-            '\x0d\x07' + '\x41' +
-            '\xc8' + '\x41' +
-            '\x0e\x00' +
-            '\x00\x00'
+            b'\x28\x00\x00\x00' +        # length
+            b'\x00\x00\x00\x00' +        # CIE_pointer (to CIE at 0)
+            b'\x44\x33\x22\x11' +        # initial_location
+            b'\x54\x00\x00\x00' +        # address range
+            b'\x41' +
+            b'\x0e\x0c' + b'\x41' +
+            b'\x88\x01' + b'\x41' +
+            b'\x86\x02' + b'\x41' +
+            b'\x0d\x06' + b'\x41' +
+            b'\x84\x03' + b'\x4b' +
+            b'\xc4' + b'\x41' +
+            b'\xc6' +
+            b'\x0d\x07' + b'\x41' +
+            b'\xc8' + b'\x41' +
+            b'\x0e\x00' +
+            b'\x00\x00'
             )
         s.write(data)
 
@@ -126,14 +126,14 @@ class TestCallFrame(unittest.TestCase):
 
     def test_describe_CFI_instructions(self):
         # The data here represents a single CIE 
-        data = ('' +
-            '\x16\x00\x00\x00' +        # length
-            '\xff\xff\xff\xff' +        # CIE_id
-            '\x03\x00\x04\x7c' +        # version, augmentation, caf, daf
-            '\x08' +                    # return address
-            '\x0c\x07\x02' +
-            '\x10\x02\x07\x03\x01\x02\x00\x00\x06\x06')
-        s = StringIO(data)
+        data = (b'' +
+            b'\x16\x00\x00\x00' +        # length
+            b'\xff\xff\xff\xff' +        # CIE_id
+            b'\x03\x00\x04\x7c' +        # version, augmentation, caf, daf
+            b'\x08' +                    # return address
+            b'\x0c\x07\x02' +
+            b'\x10\x02\x07\x03\x01\x02\x00\x00\x06\x06')
+        s = BytesIO(data)
 
         structs = DWARFStructs(little_endian=True, dwarf_format=32, address_size=4)
         cfi = CallFrameInfo(s, len(data), structs)
index d740eaf081060d79c6aa4837f76c3058f90fdf87..0effacea7667091f8ef24f4ed1236341ced8f586 100644 (file)
@@ -3,7 +3,6 @@ try:
 except ImportError:
     import unittest
 import sys
-from cStringIO import StringIO
 
 sys.path.extend(('..', '.'))
 from elftools.dwarf.descriptions import ExprDumper, set_global_machine_arch
index d3e11006875c18bc419d97fbab3714744b506f65..75c88c89d32bb894da272e065c08c76a02e1e96d 100644 (file)
@@ -3,9 +3,9 @@ try:
 except ImportError:
     import unittest
 import sys
-from cStringIO import StringIO
 
 sys.path.extend(['.', '..'])
+from elftools.common.py3compat import BytesIO, iteritems
 from elftools.dwarf.lineprogram import LineProgram, LineState, LineProgramEntry
 from elftools.dwarf.structs import DWARFStructs
 from elftools.dwarf.constants import *
@@ -17,20 +17,20 @@ class TestLineProgram(unittest.TestCase):
         """
         ds = DWARFStructs(little_endian=True, dwarf_format=32, address_size=4)
         header = ds.Dwarf_lineprog_header.parse(
-            '\x04\x10\x00\x00' +    # initial lenght
-            '\x03\x00' +            # version
-            '\x20\x00\x00\x00' +    # header length
-            '\x01\x01\x01\x0F' +    # flags
-            '\x0A' +                # opcode_base
-            '\x00\x01\x04\x08\x0C\x01\x01\x01\x00' + # standard_opcode_lengths
+            b'\x04\x10\x00\x00' +    # initial lenght
+            b'\x03\x00' +            # version
+            b'\x20\x00\x00\x00' +    # header length
+            b'\x01\x01\x01\x0F' +    # flags
+            b'\x0A' +                # opcode_base
+            b'\x00\x01\x04\x08\x0C\x01\x01\x01\x00' + # standard_opcode_lengths
             # 2 dir names followed by a NULL
-            '\x61\x62\x00\x70\x00\x00' + 
+            b'\x61\x62\x00\x70\x00\x00' + 
             # a file entry
-            '\x61\x72\x00\x0C\x0D\x0F' + 
+            b'\x61\x72\x00\x0C\x0D\x0F' + 
             # and another entry
-            '\x45\x50\x51\x00\x86\x12\x07\x08' +
+            b'\x45\x50\x51\x00\x86\x12\x07\x08' +
             # followed by NULL
-            '\x00')
+            b'\x00')
 
         lp = LineProgram(header, stream, ds, 0, len(stream.getvalue()))
         return lp
@@ -39,20 +39,20 @@ class TestLineProgram(unittest.TestCase):
         """ Assert that the state attributes specified in kwargs have the given
             values (the rest are default).
         """
-        for k, v in kwargs.iteritems():
+        for k, v in iteritems(kwargs):
             self.assertEqual(getattr(state, k), v)
         
     def test_spec_sample_59(self):
         # Sample in figure 59 of DWARFv3
-        s = StringIO()
+        s = BytesIO()
         s.write(
-            '\x02\xb9\x04' +
-            '\x0b' +
-            '\x38' +
-            '\x82' +
-            '\x73' +
-            '\x02\x02' +
-            '\x00\x01\x01')
+            b'\x02\xb9\x04' +
+            b'\x0b' +
+            b'\x38' +
+            b'\x82' +
+            b'\x73' +
+            b'\x02\x02' +
+            b'\x00\x01\x01')
 
         lp = self._make_program_in_stream(s)
         linetable = lp.get_entries()
@@ -73,18 +73,18 @@ class TestLineProgram(unittest.TestCase):
 
     def test_spec_sample_60(self):
         # Sample in figure 60 of DWARFv3
-        s = StringIO()
+        s = BytesIO()
         s.write(
-            '\x09\x39\x02' +
-            '\x0b' +
-            '\x09\x03\x00' +
-            '\x0b' +
-            '\x09\x08\x00' +
-            '\x0a' +
-            '\x09\x07\x00' +
-            '\x0a' +
-            '\x09\x02\x00' +
-            '\x00\x01\x01')
+            b'\x09\x39\x02' +
+            b'\x0b' +
+            b'\x09\x03\x00' +
+            b'\x0b' +
+            b'\x09\x08\x00' +
+            b'\x0a' +
+            b'\x09\x07\x00' +
+            b'\x0a' +
+            b'\x09\x02\x00' +
+            b'\x00\x01\x01')
 
         lp = self._make_program_in_stream(s)
         linetable = lp.get_entries()
index d85ee0fe6f535c770a4004dd31a41ac5ab95daf5..eaf972c4ee19890f7d670e6666f74f558358a905 100644 (file)
@@ -13,28 +13,28 @@ class TestDWARFStructs(unittest.TestCase):
         ds = DWARFStructs(little_endian=True, dwarf_format=32, address_size=4)
 
         c = ds.Dwarf_lineprog_header.parse(
-            '\x04\x10\x00\x00' +    # initial lenght
-            '\x05\x02' +            # version
-            '\x20\x00\x00\x00' +    # header length
-            '\x05\x10\x40\x50' +    # until and including line_range
-            '\x06' +                # opcode_base
-            '\x00\x01\x04\x08\x0C' + # standard_opcode_lengths
+            b'\x04\x10\x00\x00' +    # initial lenght
+            b'\x05\x02' +            # version
+            b'\x20\x00\x00\x00' +    # header length
+            b'\x05\x10\x40\x50' +    # until and including line_range
+            b'\x06' +                # opcode_base
+            b'\x00\x01\x04\x08\x0C' + # standard_opcode_lengths
             # 2 dir names followed by a NULL
-            '\x61\x62\x00\x70\x00\x00' + 
+            b'\x61\x62\x00\x70\x00\x00' + 
             # a file entry
-            '\x61\x72\x00\x0C\x0D\x0F' + 
+            b'\x61\x72\x00\x0C\x0D\x0F' + 
             # and another entry
-            '\x45\x50\x51\x00\x86\x12\x07\x08' +
+            b'\x45\x50\x51\x00\x86\x12\x07\x08' +
             # followed by NULL
-            '\x00')
+            b'\x00')
 
         self.assertEqual(c.version, 0x205)
         self.assertEqual(c.opcode_base, 6)
         self.assertEqual(c.standard_opcode_lengths, [0, 1, 4, 8, 12])
-        self.assertEqual(c.include_directory, ['ab', 'p'])
+        self.assertEqual(c.include_directory, [b'ab', b'p'])
         self.assertEqual(len(c.file_entry), 2)
-        self.assertEqual(c.file_entry[0].name, 'ar')
-        self.assertEqual(c.file_entry[1].name, 'EPQ')
+        self.assertEqual(c.file_entry[0].name, b'ar')
+        self.assertEqual(c.file_entry[1].name, b'EPQ')
         self.assertEqual(c.file_entry[1].dir_index, 0x12 * 128 + 6)
 
 
index a30ac3a7484eb10b716bf32d0e23550992f15e44..f0142d849d1cdf608ef6bb2a944b81378e5e485d 100644 (file)
@@ -3,46 +3,46 @@ try:
 except ImportError:
     import unittest
 import sys
-from cStringIO import StringIO
 from random import randint
 
 sys.path.extend(['.', '..'])
+from elftools.common.py3compat import int2byte, BytesIO
 from elftools.common.utils import (parse_cstring_from_stream,
         preserve_stream_pos)
 
 
 class Test_parse_cstring_from_stream(unittest.TestCase):
-    def _make_random_string(self, n):
-        return ''.join(chr(randint(32, 127)) for i in range(n))
+    def _make_random_bytes(self, n):
+        return b''.join(int2byte(randint(32, 127)) for i in range(n))
         
     def test_small1(self):
-        sio = StringIO('abcdefgh\x0012345')
-        self.assertEqual(parse_cstring_from_stream(sio), 'abcdefgh')
-        self.assertEqual(parse_cstring_from_stream(sio, 2), 'cdefgh')
-        self.assertEqual(parse_cstring_from_stream(sio, 8), '')
+        sio = BytesIO(b'abcdefgh\x0012345')
+        self.assertEqual(parse_cstring_from_stream(sio), b'abcdefgh')
+        self.assertEqual(parse_cstring_from_stream(sio, 2), b'cdefgh')
+        self.assertEqual(parse_cstring_from_stream(sio, 8), b'')
 
     def test_small2(self):
-        sio = StringIO('12345\x006789\x00abcdefg\x00iii')
-        self.assertEqual(parse_cstring_from_stream(sio), '12345')
-        self.assertEqual(parse_cstring_from_stream(sio, 5), '')
-        self.assertEqual(parse_cstring_from_stream(sio, 6), '6789')
+        sio = BytesIO(b'12345\x006789\x00abcdefg\x00iii')
+        self.assertEqual(parse_cstring_from_stream(sio), b'12345')
+        self.assertEqual(parse_cstring_from_stream(sio, 5), b'')
+        self.assertEqual(parse_cstring_from_stream(sio, 6), b'6789')
 
     def test_large1(self):
-        text = 'i' * 400 + '\x00' + 'bb'
-        sio = StringIO(text)
-        self.assertEqual(parse_cstring_from_stream(sio), 'i' * 400)
-        self.assertEqual(parse_cstring_from_stream(sio, 150), 'i' * 250)
+        text = b'i' * 400 + b'\x00' + b'bb'
+        sio = BytesIO(text)
+        self.assertEqual(parse_cstring_from_stream(sio), b'i' * 400)
+        self.assertEqual(parse_cstring_from_stream(sio, 150), b'i' * 250)
 
     def test_large2(self):
-        text = self._make_random_string(5000) + '\x00' + 'jujajaja'
-        sio = StringIO(text)
+        text = self._make_random_bytes(5000) + b'\x00' + b'jujajaja'
+        sio = BytesIO(text)
         self.assertEqual(parse_cstring_from_stream(sio), text[:5000])
         self.assertEqual(parse_cstring_from_stream(sio, 2348), text[2348:5000])
 
 
 class Test_preserve_stream_pos(object):
     def test_basic(self):
-        sio = StringIO('abcdef')
+        sio = BytesIO('abcdef')
         with preserve_stream_pos(sio):
             sio.seek(4)
         self.assertEqual(stream.tell(), 0)
index 803a9995d81330d5af50c473b8ee819773144d15..0ee0ebf95333417a1187f433eeb9aa902a2ea446 100644 (file)
@@ -7,6 +7,7 @@
 # This code is in the public domain
 #-------------------------------------------------------------------------------
 import os, subprocess, tempfile
+from elftools.common.py3compat import bytes2str
 
 
 def run_exe(exe_path, args):
@@ -19,7 +20,7 @@ def run_exe(exe_path, args):
         popen_cmd.insert(0, 'python')
     proc = subprocess.Popen(popen_cmd, stdout=subprocess.PIPE)
     proc_stdout = proc.communicate()[0]
-    return proc.returncode, proc_stdout
+    return proc.returncode, bytes2str(proc_stdout)
     
 
 def is_in_rootdir():
diff --git a/tox.ini b/tox.ini
index 4c4a5c25908c6f4e288659b7f5ae8d4ef7eb7358..73fbb84853538712d0d1202f4446b7aee3428cf9 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-envlist = py27,py26
+envlist = py27,py26,py32
 
 [testenv]
 commands =