* Added handling of segments
authoreliben <devnull@localhost>
Thu, 8 Sep 2011 11:49:30 +0000 (14:49 +0300)
committereliben <devnull@localhost>
Thu, 8 Sep 2011 11:49:30 +0000 (14:49 +0300)
* Added iteration API for sections

elftools/elf/elffile.py
elftools/elf/enums.py
elftools/elf/segments.py [new file with mode: 0644]
z.py

index 11d37041c1d5e48023ac1e2534d440ecffdcd905..01be519d33118cdb8b9573749f120c9e7ab12bfb 100644 (file)
@@ -13,6 +13,7 @@ from ..exceptions import ELFError, ELFParseError
 from ..construct import ConstructError, CString\r
 from .structs import ELFStructs\r
 from .sections import Section\r
+from .segments import Segment\r
 \r
 \r
 class ELFFile(object):\r
@@ -37,7 +38,7 @@ class ELFFile(object):
         self._stringtable = self._get_stringtable()\r
     \r
     def num_sections(self):
-        """ Get the number of sections in the file
+        """ Number of sections in the file
         """\r
         return self['e_shnum']\r
     \r
@@ -48,6 +49,29 @@ class ELFFile(object):
         name = self._get_section_name(section_header)\r
         return Section(section_header, name, self.stream)\r
     \r
+    def iter_sections(self):
+        """ Yield all the sections in the file
+        """\r
+        for i in range(self.num_sections()):\r
+            yield self.get_section(i)\r
+    \r
+    def num_segments(self):
+        """ Number of segments in the file
+        """\r
+        return self['e_phnum']\r
+    \r
+    def get_segment(self, n):
+        """ Get the segment at index #n from the file (Segment object)
+        """\r
+        segment_header = self._get_segment_header(n)\r
+        return Segment(segment_header, self.stream)\r
+    \r
+    def iter_segments(self):
+        """ Yield all the segments in the file
+        """\r
+        for i in range(self.num_segments()):\r
+            yield self.get_segment(i)\r
+    \r
     #-------------------------------- PRIVATE --------------------------------#\r
     \r
     def __getitem__(self, name):
@@ -87,12 +111,23 @@ class ELFFile(object):
         """\r
         return self['e_shoff'] + n * self['e_shentsize']\r
     \r
+    def _segment_offset(self, n):
+        """ Compute the offset of segment #n in the file
+        """\r
+        return self['e_phoff'] + n * self['e_phentsize']\r
+    \r
     def _get_section_header(self, n):
         """ Find the header of section #n, parse it and return the struct 
         """\r
         self.stream.seek(self._section_offset(n))\r
         return self._struct_parse(self.structs.Elf_Shdr)\r
     \r
+    def _get_segment_header(self, n):
+        """ Find the header of segment #n, parse it and return the struct
+        """\r
+        self.stream.seek(self._segment_offset(n))\r
+        return self._struct_parse(self.structs.Elf_Phdr)\r
+    \r
     def _get_section_name(self, section_header):
         """ Given a section header, find this section's name in the file's\r
             string table, and return it as a normal Python string.
index 1217d74773f09e15f1e6238d3e6566bed4b5d975..cdaf31611e2d4827802025022ba703562f652b3a 100644 (file)
@@ -89,6 +89,7 @@ ENUM_SH_TYPE = dict(
 )\r
 \r
 # p_type in the program header\r
+# some values scavenged from the ELF headers in binutils-2.21\r
 ENUM_P_TYPE = dict(\r
     PT_NULL=0,\r
     PT_LOAD=1,\r
@@ -99,5 +100,8 @@ ENUM_P_TYPE = dict(
     PT_PHDR=6,\r
     PT_LOPROC=0x70000000,\r
     PT_HIPROC=0x7fffffff,\r
+    PT_GNU_EH_FRAME=0x6474e550,\r
+    PT_GNU_STACK=0x6474e551,\r
+    PT_GNU_RELRO=0x6474e552,\r
 )\r
 \r
diff --git a/elftools/elf/segments.py b/elftools/elf/segments.py
new file mode 100644 (file)
index 0000000..02a81ed
--- /dev/null
@@ -0,0 +1,25 @@
+#-------------------------------------------------------------------------------\r
+# elftools: elf/segments.py\r
+#\r
+# ELF segments\r
+#\r
+# Eli Bendersky (eliben@gmail.com)\r
+# This code is in the public domain\r
+#-------------------------------------------------------------------------------\r
+\r
+class Segment(object):\r
+    def __init__(self, header, stream):\r
+        self.header = header\r
+        self.stream = stream\r
+    \r
+    def data(self):\r
+        """ The segment data from the file.\r
+        """\r
+        self.stream.seek(self['p_offset'])\r
+        return self.stream.read(self['p_filesz'])\r
+\r
+    def __getitem__(self, name):\r
+        """ Implement dict-like access to header entries\r
+        """\r
+        return self.header[name]\r
+\r
diff --git a/z.py b/z.py
index c74a4ff9f8de4279fbb954f2ab81dcfa314bc916..9f208d3ba9c6660d67a6274223022fafdae345f5 100644 (file)
--- a/z.py
+++ b/z.py
@@ -9,12 +9,18 @@ stream = open('binfiles/z.elf', 'rb')
 \r
 efile = ELFFile(stream)\r
 \r
-print 'num', efile.num_sections()\r
-sec = efile.get_section(39)\r
+for sec in efile.iter_sections():\r
+    print sec.name\r
+\r
+for seg in efile.iter_segments():\r
+    print seg['p_type'], seg['p_offset']\r
+\r
+#~ print 'num', efile.num_sections()\r
+#~ sec = efile.get_section(39)\r
 #~ print sec.header\r
-print sec.name\r
-print sec['sh_type']\r
-print map(ord, sec.data())\r
+#~ print sec.name\r
+#~ print sec['sh_type']\r
+#~ print map(ord, sec.data())\r
 \r
 #~ print sec.stream\r
 #~ print map(ord, efile._stringtable)\r