summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin H. Johnson <robbat2@gentoo.org>2015-08-08 13:49:04 -0700
committerRobin H. Johnson <robbat2@gentoo.org>2015-08-08 17:38:18 -0700
commit56bd759df1d0c750a065b8c845e93d5dfa6b549d (patch)
tree3f91093cdb475e565ae857f1c5a7fd339e2d781e /dev-python/pyelftools
downloadgentoo-56bd759df1d0c750a065b8c845e93d5dfa6b549d.tar.gz
gentoo-56bd759df1d0c750a065b8c845e93d5dfa6b549d.tar.bz2
gentoo-56bd759df1d0c750a065b8c845e93d5dfa6b549d.zip
proj/gentoo: Initial commit
This commit represents a new era for Gentoo: Storing the gentoo-x86 tree in Git, as converted from CVS. This commit is the start of the NEW history. Any historical data is intended to be grafted onto this point. Creation process: 1. Take final CVS checkout snapshot 2. Remove ALL ChangeLog* files 3. Transform all Manifests to thin 4. Remove empty Manifests 5. Convert all stale $Header$/$Id$ CVS keywords to non-expanded Git $Id$ 5.1. Do not touch files with -kb/-ko keyword flags. Signed-off-by: Robin H. Johnson <robbat2@gentoo.org> X-Thanks: Alec Warner <antarus@gentoo.org> - did the GSoC 2006 migration tests X-Thanks: Robin H. Johnson <robbat2@gentoo.org> - infra guy, herding this project X-Thanks: Nguyen Thai Ngoc Duy <pclouds@gentoo.org> - Former Gentoo developer, wrote Git features for the migration X-Thanks: Brian Harring <ferringb@gentoo.org> - wrote much python to improve cvs2svn X-Thanks: Rich Freeman <rich0@gentoo.org> - validation scripts X-Thanks: Patrick Lauer <patrick@gentoo.org> - Gentoo dev, running new 2014 work in migration X-Thanks: Michał Górny <mgorny@gentoo.org> - scripts, QA, nagging X-Thanks: All of other Gentoo developers - many ideas and lots of paint on the bikeshed
Diffstat (limited to 'dev-python/pyelftools')
-rw-r--r--dev-python/pyelftools/Manifest3
-rw-r--r--dev-python/pyelftools/files/pyelftools-0.21-dyntable.patch143
-rw-r--r--dev-python/pyelftools/files/pyelftools-0.22-dyntable.patch153
-rw-r--r--dev-python/pyelftools/files/pyelftools-0.22-grace-string-dyn.patch75
-rw-r--r--dev-python/pyelftools/metadata.xml12
-rw-r--r--dev-python/pyelftools/pyelftools-0.21-r4.ebuild29
-rw-r--r--dev-python/pyelftools/pyelftools-0.22.ebuild35
-rw-r--r--dev-python/pyelftools/pyelftools-0.23-r1.ebuild30
-rw-r--r--dev-python/pyelftools/pyelftools-0.23.ebuild30
9 files changed, 510 insertions, 0 deletions
diff --git a/dev-python/pyelftools/Manifest b/dev-python/pyelftools/Manifest
new file mode 100644
index 000000000000..60d5166383b2
--- /dev/null
+++ b/dev-python/pyelftools/Manifest
@@ -0,0 +1,3 @@
+DIST pyelftools-0.21.tar.gz 283250 SHA256 a9a10d894c698ab3a2d909c3df1c3d88d0ab03811351c278b3f520204f33d834 SHA512 adddfe10756a26d694bb4a048104b04958337dc7a1ab023e4bb50b7fbf5d66fc5b6c4a077699757adb26bd6ffd8885a1908f3daae3d0acd65a704a11499308d3 WHIRLPOOL 1607c311e7b3ec463afe53b239f84f7b47878a613365c2f8809a15df4e5096d7d702a8dcbc91c357b3d5f28297106abaa16540842ad09a4dc2bdd1a648589389
+DIST pyelftools-0.22.tar.gz 395525 SHA256 9f7dd617b8a577a3834e7dd7f34f49df21c0670e67a48b21add19abe1adffb60 SHA512 10a84d9d0e28cb609f252990fbc05747e0840c5efeeb6890e13076aa2d59780c7d1a5bd6036dee6f8b252a984796a3834183ccab1c1988473bc69646fe56867b WHIRLPOOL eac57cef3f4159deac907394995655e227aa1d034a3b4ec54728531d08ef1b4f8edee33d971a3423b32d08efba621496bb5e778ba090bc264db6d006da4f8842
+DIST pyelftools-0.23.tar.gz 401363 SHA256 fc57aadd096e8f9b9b03f1a9578f673ee645e1513a5ff0192ef439e77eab21de SHA512 47102b2b0c69f357ba1c6af8e45157cd5395a74aaaf10fcccbf5b2d584a494aa16b1f6d08599459ae036f45888cb0fe422cb3241458e6ee0f1e8e1f32b3ae5d0 WHIRLPOOL 1492b08020bb7a106b939c8691f9910949a9d36241a8379f5358832b7b79a6ac1fdac4aaa928d65cd25fe466cb96bb38ef383bd9e79ae5fe0417aad53a1387a4
diff --git a/dev-python/pyelftools/files/pyelftools-0.21-dyntable.patch b/dev-python/pyelftools/files/pyelftools-0.21-dyntable.patch
new file mode 100644
index 000000000000..e43e6cb0a4db
--- /dev/null
+++ b/dev-python/pyelftools/files/pyelftools-0.21-dyntable.patch
@@ -0,0 +1,143 @@
+changeset: 207:92736c403d53
+tag: tip
+user: Mike Frysinger <vapier@gentoo.org>
+date: Mon Apr 22 19:02:21 2013 -0400
+summary: support parsing of dynamic ELFs w/out section headers
+
+At runtime, ELFs do not use the section headers at all. Instead, only
+the program segments and dynamic tags get used. This means you can
+strip the section table completely from an ELF and have it still work.
+
+In practice, people rarely do this, but it's not unheard of. Make the
+Dynamic tags work even in these cases by loading the strings table the
+same way the runtime loader does:
+- parse the symtab address from DT_STRTAB
+- locate the file offset via the program segments
+
+In order to avoid circular deps (parsing a dyntag requires walking parsed
+dyntags), add a set of internal funcs for returning the raw values.
+
+diff --git a/elftools/elf/dynamic.py b/elftools/elf/dynamic.py
+--- a/elftools/elf/dynamic.py
++++ b/elftools/elf/dynamic.py
+@@ -10,11 +10,26 @@
+
+ from .sections import Section
+ from .segments import Segment
+-from ..common.utils import struct_parse
++from ..common.utils import struct_parse, parse_cstring_from_stream
+
+ from .enums import ENUM_D_TAG
+
+
++class _DynamicStringTable(object):
++ """ Bare string table based on values found via ELF dynamic tags and
++ loadable segments only. Good enough for get_string() only.
++ """
++ def __init__(self, stream, table_offset):
++ self._stream = stream
++ self._table_offset = table_offset
++
++ def get_string(self, offset):
++ """ Get the string stored at the given offset in this string table.
++ """
++ return parse_cstring_from_stream(self._stream,
++ self._table_offset + offset)
++
++
+ class DynamicTag(object):
+ """ Dynamic Tag object - representing a single dynamic tag entry from a
+ dynamic section.
+@@ -27,10 +42,9 @@
+ _HANDLED_TAGS = frozenset(
+ ['DT_NEEDED', 'DT_RPATH', 'DT_RUNPATH', 'DT_SONAME'])
+
+- def __init__(self, entry, elffile):
++ def __init__(self, entry, dynstr):
+ self.entry = entry
+- if entry.d_tag in self._HANDLED_TAGS:
+- dynstr = elffile.get_section_by_name(b'.dynstr')
++ if entry.d_tag in self._HANDLED_TAGS and dynstr:
+ setattr(self, entry.d_tag[3:].lower(),
+ dynstr.get_string(self.entry.d_val))
+
+@@ -60,26 +74,66 @@
+ self._num_tags = -1
+ self._offset = position
+ self._tagsize = self._elfstructs.Elf_Dyn.sizeof()
++ self.__string_table = None
++
++ @property
++ def _string_table(self):
++ if self.__string_table:
++ return self.__string_table
++
++ # If the ELF has stripped its section table (which is unusual, but
++ # perfectly valid), we need to use the dynamic tags to locate the
++ # dynamic string table.
++ strtab = None
++ for tag in self._iter_tags(type='DT_STRTAB'):
++ strtab = tag['d_val']
++ break
++ # If we found a dynamic string table, locate the offset in the file
++ # by using the program headers.
++ if strtab:
++ for segment in self._elffile.iter_segments():
++ if (strtab >= segment['p_vaddr'] and
++ strtab < segment['p_vaddr'] + segment['p_filesz']):
++ self.__string_table = _DynamicStringTable(
++ self._stream,
++ segment['p_offset'] + (strtab - segment['p_vaddr']))
++ return self.__string_table
++
++ # That didn't work for some reason. Let's use the section header
++ # even though this ELF is super weird.
++ self.__string_table = self._elffile.get_section_by_name(b'.dynstr')
++
++ return self.__string_table
++
++ def _iter_tags(self, type=None):
++ """ Yield all raw tags (limit to |type| if specified)
++ """
++ for n in itertools.count():
++ tag = self._get_tag(n)
++ if type is None or tag['d_tag'] == type:
++ yield tag
++ if tag['d_tag'] == 'DT_NULL':
++ break
+
+ def iter_tags(self, type=None):
+ """ Yield all tags (limit to |type| if specified)
+ """
+- for n in itertools.count():
+- tag = self.get_tag(n)
+- if type is None or tag.entry.d_tag == type:
+- yield tag
+- if tag.entry.d_tag == 'DT_NULL':
+- break
++ for tag in self._iter_tags(type=type):
++ yield DynamicTag(tag, self._string_table)
++
++ def _get_tag(self, n):
++ """ Get the raw tag at index #n from the file
++ """
++ offset = self._offset + n * self._tagsize
++ return struct_parse(
++ self._elfstructs.Elf_Dyn,
++ self._stream,
++ stream_pos=offset)
+
+ def get_tag(self, n):
+ """ Get the tag at index #n from the file (DynamicTag object)
+ """
+- offset = self._offset + n * self._tagsize
+- entry = struct_parse(
+- self._elfstructs.Elf_Dyn,
+- self._stream,
+- stream_pos=offset)
+- return DynamicTag(entry, self._elffile)
++ return DynamicTag(self._get_tag(n), self._string_table)
+
+ def num_tags(self):
+ """ Number of dynamic tags in the file
+
diff --git a/dev-python/pyelftools/files/pyelftools-0.22-dyntable.patch b/dev-python/pyelftools/files/pyelftools-0.22-dyntable.patch
new file mode 100644
index 000000000000..7f7730499820
--- /dev/null
+++ b/dev-python/pyelftools/files/pyelftools-0.22-dyntable.patch
@@ -0,0 +1,153 @@
+From b3157177bde20a2b0d0ada7b2ba44144ee5aea6f Mon Sep 17 00:00:00 2001
+From: Mike Frysinger <vapier@gentoo.org>
+Date: Sun, 9 Jun 2013 18:42:40 -0400
+Subject: [PATCH] support parsing of dynamic ELFs w/out section headers
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+At runtime, ELFs do not use the section headers at all. Instead, only
+the program segments and dynamic tags get used. This means you can
+strip the section table completely from an ELF and have it still work.
+
+In practice, people rarely do this, but it's not unheard of. Make the
+Dynamic tags work even in these cases by loading the strings table the
+same way the runtime loader does:
+ * parse the symtab address from DT_STRTAB
+ * locate the file offset via the program segments
+
+In order to avoid circular deps (parsing a dyntag requires walking parsed
+dyntags), add a set of internal funcs for returning the raw values.
+
+You can see this in action:
+$ eu-strip -g --strip-sections a.out
+$ readelf -S a.out
+<nothing>
+$ lddtree.py ./a.out
+a.out (interpreter => /lib64/ld-linux-x86-64.so.2)
+ libïäöëß.so => None
+ libc.so.6 => /lib64/libc.so.6
+
+Signed-off-by: Mike Frysinger <vapier@gentoo.org>
+---
+ elftools/elf/dynamic.py | 81 ++++++++++++++++++---
+ test/test_dynamic.py | 28 ++++++-
+ .../aarch64_super_stripped.elf | Bin 0 -> 4136 bytes
+ 3 files changed, 97 insertions(+), 12 deletions(-)
+ create mode 100755 test/testfiles_for_unittests/aarch64_super_stripped.elf
+
+diff --git a/elftools/elf/dynamic.py b/elftools/elf/dynamic.py
+index d9db870..ad5111f 100644
+--- a/elftools/elf/dynamic.py
++++ b/elftools/elf/dynamic.py
+@@ -11,9 +11,22 @@ import itertools
+ 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
++from ..common.utils import struct_parse, parse_cstring_from_stream
++
++
++class _DynamicStringTable(object):
++ """ Bare string table based on values found via ELF dynamic tags and
++ loadable segments only. Good enough for get_string() only.
++ """
++ def __init__(self, stream, table_offset):
++ self._stream = stream
++ self._table_offset = table_offset
++
++ def get_string(self, offset):
++ """ Get the string stored at the given offset in this string table.
++ """
++ return parse_cstring_from_stream(self._stream,
++ self._table_offset + offset)
+
+
+ class DynamicTag(object):
+@@ -61,27 +76,71 @@ class Dynamic(object):
+ self._num_tags = -1
+ self._offset = position
+ self._tagsize = self._elfstructs.Elf_Dyn.sizeof()
+- self._stringtable = stringtable
++ self.__stringtable = stringtable
+
+- def iter_tags(self, type=None):
+- """ Yield all tags (limit to |type| if specified)
++ @property
++ def _stringtable(self):
++ """ Return a string table for looking up dynamic tag related strings.
++
++ This won't be a "full" string table object, but will at least support
++ the get_string() function.
++ """
++ if self.__stringtable:
++ return self.__stringtable
++
++ # If the ELF has stripped its section table (which is unusual, but
++ # perfectly valid), we need to use the dynamic tags to locate the
++ # dynamic string table.
++ strtab = None
++ for tag in self._iter_tags(type='DT_STRTAB'):
++ strtab = tag['d_val']
++ break
++ # If we found a dynamic string table, locate the offset in the file
++ # by using the program headers.
++ if strtab:
++ for segment in self._elffile.iter_segments():
++ if (strtab >= segment['p_vaddr'] and
++ strtab < segment['p_vaddr'] + segment['p_filesz']):
++ self.__stringtable = _DynamicStringTable(
++ self._stream,
++ segment['p_offset'] + (strtab - segment['p_vaddr']))
++ return self.__stringtable
++
++ # That didn't work for some reason. Let's use the section header
++ # even though this ELF is super weird.
++ self.__stringtable = self._elffile.get_section_by_name(b'.dynstr')
++
++ return self.__stringtable
++
++ def _iter_tags(self, type=None):
++ """ Yield all raw tags (limit to |type| if specified)
+ """
+ for n in itertools.count():
+- tag = self.get_tag(n)
+- if type is None or tag.entry.d_tag == type:
++ tag = self._get_tag(n)
++ if type is None or tag['d_tag'] == type:
+ yield tag
+- if tag.entry.d_tag == 'DT_NULL':
++ if tag['d_tag'] == 'DT_NULL':
+ break
+
+- def get_tag(self, n):
+- """ Get the tag at index #n from the file (DynamicTag object)
++ def iter_tags(self, type=None):
++ """ Yield all tags (limit to |type| if specified)
++ """
++ for tag in self._iter_tags(type=type):
++ yield DynamicTag(tag, self._stringtable)
++
++ def _get_tag(self, n):
++ """ Get the raw tag at index #n from the file
+ """
+ offset = self._offset + n * self._tagsize
+- entry = struct_parse(
++ return struct_parse(
+ self._elfstructs.Elf_Dyn,
+ self._stream,
+ stream_pos=offset)
+- return DynamicTag(entry, self._stringtable)
++
++ def get_tag(self, n):
++ """ Get the tag at index #n from the file (DynamicTag object)
++ """
++ return DynamicTag(self._get_tag(n), self._stringtable)
+
+ def num_tags(self):
+ """ Number of dynamic tags in the file
+--
+2.0.0
+
diff --git a/dev-python/pyelftools/files/pyelftools-0.22-grace-string-dyn.patch b/dev-python/pyelftools/files/pyelftools-0.22-grace-string-dyn.patch
new file mode 100644
index 000000000000..1c9552d02720
--- /dev/null
+++ b/dev-python/pyelftools/files/pyelftools-0.22-grace-string-dyn.patch
@@ -0,0 +1,75 @@
+From 80305ad20ebd481dde19fa7ff2d90249269aa588 Mon Sep 17 00:00:00 2001
+From: Eli Bendersky <eliben@gmail.com>
+Date: Wed, 23 Apr 2014 16:44:11 -0700
+Subject: [PATCH] Issue #29: Fail more gracefully when no string table is found
+ for dynamic.
+
+---
+ elftools/elf/dynamic.py | 4 ++++
+ test/test_dynamic.py | 25 +++++++++++++++++++++++++
+ 2 files changed, 29 insertions(+)
+ create mode 100644 test/test_dynamic.py
+
+diff --git a/elftools/elf/dynamic.py b/elftools/elf/dynamic.py
+index e36598e..6f88bf9 100644
+--- a/elftools/elf/dynamic.py
++++ b/elftools/elf/dynamic.py
+@@ -10,6 +10,7 @@ import itertools
+
+ 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
+@@ -29,6 +30,8 @@ class DynamicTag(object):
+ '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 +117,7 @@ class DynamicSegment(Segment, Dynamic):
+ # 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/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()
+--
+2.0.0
+
diff --git a/dev-python/pyelftools/metadata.xml b/dev-python/pyelftools/metadata.xml
new file mode 100644
index 000000000000..ec397e2251e1
--- /dev/null
+++ b/dev-python/pyelftools/metadata.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE pkgmetadata SYSTEM "http://www.gentoo.org/dtd/metadata.dtd">
+<pkgmetadata>
+ <herd>python</herd>
+ <maintainer>
+ <email>vapier@gentoo.org</email>
+ </maintainer>
+ <upstream>
+ <remote-id type="pypi">pyelftools</remote-id>
+ <remote-id type="github">eliben/pyelftools</remote-id>
+ </upstream>
+</pkgmetadata>
diff --git a/dev-python/pyelftools/pyelftools-0.21-r4.ebuild b/dev-python/pyelftools/pyelftools-0.21-r4.ebuild
new file mode 100644
index 000000000000..778f664f9c8d
--- /dev/null
+++ b/dev-python/pyelftools/pyelftools-0.21-r4.ebuild
@@ -0,0 +1,29 @@
+# Copyright 1999-2015 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+EAPI="4"
+
+PYTHON_COMPAT=( python{2_7,3_3} )
+inherit distutils-r1
+
+DESCRIPTION="pure-Python library for parsing and analyzing ELF files and DWARF debugging information"
+HOMEPAGE="http://pypi.python.org/pypi/pyelftools https://github.com/eliben/pyelftools"
+SRC_URI="mirror://pypi/${PN:0:1}/${PN}/${P}.tar.gz"
+
+LICENSE="public-domain"
+SLOT="0"
+KEYWORDS="alpha amd64 arm arm64 hppa ia64 m68k ~mips ppc ppc64 s390 sh sparc x86 ~amd64-fbsd ~amd64-linux ~sparc-fbsd ~x86-fbsd ~x86-linux"
+IUSE=""
+
+src_prepare() {
+ epatch "${FILESDIR}"/${P}-dyntable.patch
+}
+
+python_test() {
+ # readelf_tests often fails due to host `readelf` changing output format
+ local t
+ for t in all_unittests examples_test ; do
+ "${PYTHON}" ./test/run_${t}.py || die "Tests fail with ${EPYTHON}"
+ done
+}
diff --git a/dev-python/pyelftools/pyelftools-0.22.ebuild b/dev-python/pyelftools/pyelftools-0.22.ebuild
new file mode 100644
index 000000000000..7e97efcb9b22
--- /dev/null
+++ b/dev-python/pyelftools/pyelftools-0.22.ebuild
@@ -0,0 +1,35 @@
+# Copyright 1999-2015 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+EAPI="5"
+
+PYTHON_COMPAT=( python{2_7,3_3,3_4} )
+inherit distutils-r1
+
+DESCRIPTION="pure-Python library for parsing and analyzing ELF files and DWARF debugging information"
+HOMEPAGE="http://pypi.python.org/pypi/pyelftools https://github.com/eliben/pyelftools"
+SRC_URI="mirror://pypi/${PN:0:1}/${PN}/${P}.tar.gz"
+
+LICENSE="public-domain"
+SLOT="0"
+KEYWORDS="alpha amd64 arm arm64 hppa ia64 m68k ~mips ppc ppc64 s390 sh sparc x86 ~amd64-fbsd ~sparc-fbsd ~x86-fbsd ~amd64-linux ~x86-linux"
+IUSE="examples"
+
+PATCHES=(
+ "${FILESDIR}"/${P}-grace-string-dyn.patch
+ "${FILESDIR}"/${P}-dyntable.patch
+)
+
+python_test() {
+ # readelf_tests often fails due to host `readelf` changing output format
+ local t
+ for t in all_unittests examples_test ; do
+ "${PYTHON}" ./test/run_${t}.py || die "Tests fail with ${EPYTHON}"
+ done
+}
+
+python_install_all() {
+ use examples && local EXAMPLES=( examples/. )
+ distutils-r1_python_install_all
+}
diff --git a/dev-python/pyelftools/pyelftools-0.23-r1.ebuild b/dev-python/pyelftools/pyelftools-0.23-r1.ebuild
new file mode 100644
index 000000000000..6ce449e729fb
--- /dev/null
+++ b/dev-python/pyelftools/pyelftools-0.23-r1.ebuild
@@ -0,0 +1,30 @@
+# Copyright 1999-2015 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+EAPI="5"
+
+PYTHON_COMPAT=( python{2_7,3_3,3_4} )
+inherit distutils-r1
+
+DESCRIPTION="pure-Python library for parsing and analyzing ELF files and DWARF debugging information"
+HOMEPAGE="http://pypi.python.org/pypi/pyelftools https://github.com/eliben/pyelftools"
+SRC_URI="mirror://pypi/${PN:0:1}/${PN}/${P}.tar.gz"
+
+LICENSE="public-domain"
+SLOT="0"
+KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~m68k ~mips ~ppc ~ppc64 ~s390 ~sh ~sparc ~x86 ~amd64-fbsd ~sparc-fbsd ~x86-fbsd ~amd64-linux ~x86-linux"
+IUSE="examples"
+
+python_test() {
+ # readelf_tests often fails due to host `readelf` changing output format
+ local t
+ for t in all_unittests examples_test ; do
+ "${PYTHON}" ./test/run_${t}.py || die "Tests fail with ${EPYTHON}"
+ done
+}
+
+python_install_all() {
+ use examples && local EXAMPLES=( examples/. )
+ distutils-r1_python_install_all
+}
diff --git a/dev-python/pyelftools/pyelftools-0.23.ebuild b/dev-python/pyelftools/pyelftools-0.23.ebuild
new file mode 100644
index 000000000000..afaebf9bd7db
--- /dev/null
+++ b/dev-python/pyelftools/pyelftools-0.23.ebuild
@@ -0,0 +1,30 @@
+# Copyright 1999-2014 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+EAPI="4"
+
+PYTHON_COMPAT=( python{2_7,3_3,3_4} )
+inherit distutils-r1
+
+DESCRIPTION="pure-Python library for parsing and analyzing ELF files and DWARF debugging information"
+HOMEPAGE="http://pypi.python.org/pypi/pyelftools https://github.com/eliben/pyelftools"
+SRC_URI="mirror://pypi/${PN:0:1}/${PN}/${P}.tar.gz"
+
+LICENSE="public-domain"
+SLOT="0"
+KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ia64 ~m68k ~mips ~ppc ~ppc64 ~s390 ~sh ~sparc ~x86 ~amd64-fbsd ~sparc-fbsd ~x86-fbsd ~amd64-linux ~x86-linux"
+IUSE="examples"
+
+python_test() {
+ # readelf_tests often fails due to host `readelf` changing output format
+ local t
+ for t in all_unittests examples_test ; do
+ "${PYTHON}" ./test/run_${t}.py || die "Tests fail with ${EPYTHON}"
+ done
+}
+
+python_install_all() {
+ use examples && local EXAMPLES=( examples/. )
+ distutils-r1_python_install_all
+}