Merge pull request #37 from vadmium/map

Add ELFFile.map() method to get file offset from memory address
diff --git a/CHANGES b/CHANGES
index e45ebb0..926dbe0 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,7 +1,7 @@
 Changelog
 =========
 
-+ Version 0.22 (??)
++ Version 0.22 (30.03.2014)
 
   - pyelftools repository moved to https://github.com/eliben/pyelftools
   - Support for version sections - contributed by Yann Rouillard.
@@ -35,4 +35,3 @@
     on Windows.
 
 + Version 0.10 - Initial public release (06.01.2012)
-
diff --git a/TODO b/TODO
index 7ee53e3..9028044 100644
--- a/TODO
+++ b/TODO
@@ -4,7 +4,7 @@
 * Update elftools/__init__.py
 * Update setup.py
 * Update CHANGES
-* Tag in hg
+* Tag in git (v0.xx)
 
 construct
 ---------
@@ -22,15 +22,11 @@
 Preparing a new release
 -----------------------
 
-* Run readelf tests with up-to-date readelf (from the new binutils)
-* Run all tests with Python 2.7 before packaging, on Linux
+* Run 'tox' tests (with '-r' to create new venvs)
 * Make sure new version was updated everywhere appropriate
-* Packaging done on Linux
 * Run ``python setup.py build sdist`` (no 'upload' yet)
 * Untar the created ``dist/pyelftools-x.y.tar.gz`` and make sure
   everything looks ok
-* Runt 'tox' tests (with '-r' to create new venvs)
 * Now build with upload to send it to PyPi
 * Test with pip install from some new virtualenv
 * The older download can be kept alive for a couple of days
-
diff --git a/elftools/__init__.py b/elftools/__init__.py
index 90be2eb..8a3e56c 100644
--- a/elftools/__init__.py
+++ b/elftools/__init__.py
@@ -4,5 +4,4 @@
 # Eli Bendersky (eliben@gmail.com)
 # This code is in the public domain
 #-------------------------------------------------------------------------------
-__version__ = '0.21'
-
+__version__ = '0.22'
diff --git a/elftools/elf/dynamic.py b/elftools/elf/dynamic.py
index e36598e..d9db870 100644
--- a/elftools/elf/dynamic.py
+++ b/elftools/elf/dynamic.py
@@ -10,10 +10,9 @@
 
 from .sections import Section
 from .segments import Segment
+from ..common.exceptions import ELFError
 from ..common.utils import struct_parse
 
-from .enums import ENUM_D_TAG
-
 
 class DynamicTag(object):
     """ Dynamic Tag object - representing a single dynamic tag entry from a
@@ -29,6 +28,8 @@
          'DT_SUNW_FILTER'])
 
     def __init__(self, entry, stringtable):
+        if stringtable is None:
+            raise ELFError('Creating DynamicTag without string table')
         self.entry = entry
         if entry.d_tag in self._HANDLED_TAGS:
             setattr(self, entry.d_tag[3:].lower(),
@@ -114,6 +115,7 @@
         # So we must look for the dynamic section contained in the dynamic
         # segment, we do so by searching for the dynamic section whose content
         # is located at the same offset as the dynamic segment
+        stringtable = None
         for section in elffile.iter_sections():
             if (isinstance(section, DynamicSection) and
                     section['sh_offset'] == header['p_offset']):
diff --git a/elftools/elf/elffile.py b/elftools/elf/elffile.py
index 320a232..660cca9 100644
--- a/elftools/elf/elffile.py
+++ b/elftools/elf/elffile.py
@@ -151,7 +151,7 @@
         return DWARFInfo(
                 config=DwarfConfig(
                     little_endian=self.little_endian,
-                    default_address_size=self.elfclass / 8,
+                    default_address_size=self.elfclass // 8,
                     machine_arch=self.get_machine_arch()),
                 debug_info_sec=debug_sections[b'.debug_info'],
                 debug_abbrev_sec=debug_sections[b'.debug_abbrev'],
diff --git a/elftools/elf/sections.py b/elftools/elf/sections.py
index ce62450..1380d6b 100644
--- a/elftools/elf/sections.py
+++ b/elftools/elf/sections.py
@@ -6,7 +6,6 @@
 # Eli Bendersky (eliben@gmail.com)
 # This code is in the public domain
 #-------------------------------------------------------------------------------
-from ..construct import CString
 from ..common.utils import struct_parse, elf_assert, parse_cstring_from_stream
 
 
@@ -41,6 +40,8 @@
 
     def __eq__(self, other):
         return self.header == other.header
+    def __hash__(self):
+        return hash(self.header)
 
 
 class NullSection(Section):
@@ -77,9 +78,9 @@
         self.elfstructs = self.elffile.structs
         self.stringtable = stringtable
         elf_assert(self['sh_entsize'] > 0,
-                'Expected entry size of section %s to be > 0' % name)
+                'Expected entry size of section %r to be > 0' % name)
         elf_assert(self['sh_size'] % self['sh_entsize'] == 0,
-                'Expected section size to be a multiple of entry size in section %s' % name)
+                'Expected section size to be a multiple of entry size in section %r' % name)
 
     def num_symbols(self):
         """ Number of symbols in the table
diff --git a/scripts/readelf.py b/scripts/readelf.py
index 3263cfe..8179c01 100755
--- a/scripts/readelf.py
+++ b/scripts/readelf.py
@@ -350,11 +350,9 @@
                     parsed = 'Library runpath: [%s]' % bytes2str(tag.runpath)
                 elif tag.entry.d_tag == 'DT_SONAME':
                     parsed = 'Library soname: [%s]' % bytes2str(tag.soname)
-                elif (tag.entry.d_tag.endswith('SZ') or
-                      tag.entry.d_tag.endswith('ENT')):
+                elif tag.entry.d_tag.endswith(('SZ', 'ENT')):
                     parsed = '%i (bytes)' % tag['d_val']
-                elif (tag.entry.d_tag.endswith('NUM') or
-                      tag.entry.d_tag.endswith('COUNT')):
+                elif tag.entry.d_tag.endswith(('NUM', 'COUNT')):
                     parsed = '%i' % tag['d_val']
                 elif tag.entry.d_tag == 'DT_PLTREL':
                     s = describe_dyn_tag(tag.entry.d_val)
diff --git a/setup.py b/setup.py
index 7270411..3fed12d 100644
--- a/setup.py
+++ b/setup.py
@@ -24,7 +24,7 @@
     description='Library for analyzing ELF files and DWARF debugging information',

     long_description=description,

     license='Public domain',

-    version='0.21',

+    version='0.22',

     author='Eli Bendersky',

     maintainer='Eli Bendersky',

     author_email='eliben@gmail.com',

diff --git a/test/test_dynamic.py b/test/test_dynamic.py
new file mode 100644
index 0000000..0ee9b35
--- /dev/null
+++ b/test/test_dynamic.py
@@ -0,0 +1,25 @@
+#-------------------------------------------------------------------------------
+# elftools tests
+#
+# Eli Bendersky (eliben@gmail.com)
+# 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.common.exceptions import ELFError
+from elftools.elf.dynamic import DynamicTag
+
+
+class TestDynamicTag(unittest.TestCase):
+    def test_requires_stringtable(self):
+        with self.assertRaises(ELFError):
+            dt = DynamicTag('', None)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tox.ini b/tox.ini
index 2adfc88..600ca1c 100644
--- a/tox.ini
+++ b/tox.ini
@@ -10,4 +10,3 @@
 [testenv:py26]
 deps =
     unittest2
-