Add .stab section parser (#137)
authorPromyLOPh <lars@6xq.net>
Sat, 25 Feb 2017 15:50:52 +0000 (16:50 +0100)
committerEli Bendersky <eliben@users.noreply.github.com>
Sat, 25 Feb 2017 15:50:52 +0000 (07:50 -0800)
* Add .stab section parser

* Replace tabs with spaces

* Add unit test for stabs parser

elftools/elf/elffile.py
elftools/elf/sections.py
elftools/elf/structs.py
test/test_stab.py [new file with mode: 0644]
test/testfiles_for_unittests/obj_stabs.S [new file with mode: 0644]
test/testfiles_for_unittests/obj_stabs.elf [new file with mode: 0644]

index 64fd479b55b09f0f4e80f259852540ab62768b0e..20e070dc4661bb120b5b25fb7e46f34b1b56c98e 100644 (file)
@@ -24,7 +24,8 @@ from ..common.utils import struct_parse, elf_assert
 from .structs import ELFStructs
 from .sections import (
         Section, StringTableSection, SymbolTableSection,
-        SUNWSyminfoTableSection, NullSection, NoteSection)
+        SUNWSyminfoTableSection, NullSection, NoteSection,
+        StabSection)
 from .dynamic import DynamicSection, DynamicSegment
 from .relocation import RelocationSection, RelocationHandler
 from .gnuversions import (
@@ -308,6 +309,8 @@ class ELFFile(object):
             return DynamicSection(section_header, name, self.stream, self)
         elif sectype == 'SHT_NOTE':
             return NoteSection(section_header, name, self.stream, self)
+        elif sectype == 'SHT_PROGBITS' and name == '.stab':
+            return StabSection(section_header, name, self.stream, self)
         else:
             return Section(section_header, name, self.stream)
 
index 1bc17157c3f58dc583f56d451d65fae011a0b898..c7729586045f067646cf082f36bcd0b8e1b4479d 100644 (file)
@@ -195,3 +195,28 @@ class NoteSection(Section):
             others.
         """
         return iter_notes(self.elffile, self['sh_offset'], self['sh_size'])
+
+class StabSection(Section):
+    """ ELF stab section.
+    """
+    def __init__(self, header, name, stream, elffile):
+        super(StabSection, self).__init__(header, name, stream)
+        self.elffile = elffile
+
+    def iter_stabs(self):
+        """ Yield all stab entries.  Result type is ELFStructs.Elf_Stabs.
+        """
+        elffile = self.elffile
+        offset = self['sh_offset']
+        size = self['sh_size']
+        end = offset + size
+        while offset < end:
+            stabs = struct_parse(
+                elffile.structs.Elf_Stabs,
+                elffile.stream,
+                stream_pos=offset)
+            stabs['n_offset'] = offset
+            offset += elffile.structs.Elf_Stabs.sizeof()
+            elffile.stream.seek(offset)
+            yield stabs
+
index d2404ab7b5ac3267d96dbb48e33490f849089f84..8cbeb5cb465313913db997ecc99075e2b014bba4 100644 (file)
@@ -78,6 +78,7 @@ class ELFStructs(object):
         self._create_gnu_verdef()
         self._create_gnu_versym()
         self._create_note()
+        self._create_stabs()
 
     def _create_ehdr(self):
         self.Elf_Ehdr = Struct('Elf_Ehdr',
@@ -269,3 +270,14 @@ class ELFStructs(object):
             self.Elf_word('abi_minor'),
             self.Elf_word('abi_tiny'),
         )
+
+    def _create_stabs(self):
+        # Structure of one stabs entry, see binutils/bfd/stabs.c
+        # Names taken from https://sourceware.org/gdb/current/onlinedocs/stabs.html#Overview
+        self.Elf_Stabs = Struct('Elf_Stabs',
+            self.Elf_word('n_strx'),
+            self.Elf_byte('n_type'),
+            self.Elf_byte('n_other'),
+            self.Elf_half('n_desc'),
+            self.Elf_word('n_value'),
+        )
diff --git a/test/test_stab.py b/test/test_stab.py
new file mode 100644 (file)
index 0000000..83067b8
--- /dev/null
@@ -0,0 +1,38 @@
+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.sections import StabSection
+
+class TestStab(unittest.TestCase):
+    def test_stab(self):
+        expected = [
+            ("obj_stabs.S", 0, 0, 0x2, 33), # generated by compiler
+            ("label", 0x95, 0xc8, 0x4072, 0xdeadbeef),
+            ("another label", 0x41, 0x66, 0xf9b1, 0xcafebabe),
+            ]
+        with open(os.path.join('test', 'testfiles_for_unittests',
+                               'obj_stabs.elf'), 'rb') as f:
+            elf = ELFFile(f)
+
+            # using correct type?
+            for s in elf.iter_sections():
+                if s.name == '.stab':
+                    self.assertIsInstance (s, StabSection)
+
+            # check section contents
+            stab = elf.get_section_by_name('.stab')
+            stabstr = elf.get_section_by_name('.stabstr')
+            for entry, golden in zip (stab.iter_stabs (), expected):
+                self.assertEqual(stabstr.get_string (entry.n_strx), golden[0])
+                self.assertEqual(entry.n_type, golden[1])
+                self.assertEqual(entry.n_other, golden[2])
+                self.assertEqual(entry.n_desc, golden[3])
+                self.assertEqual(entry.n_value, golden[4])
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/test/testfiles_for_unittests/obj_stabs.S b/test/testfiles_for_unittests/obj_stabs.S
new file mode 100644 (file)
index 0000000..ecdc5b4
--- /dev/null
@@ -0,0 +1,3 @@
+# gcc -c -o obj_stabs.o obj_stabs.S
+.stabs "label", 0x95, 0xc8, 0x4072, 0xdeadbeef
+.stabs "another label", 0x41, 0x66, 0xf9b1, 0xcafebabe
diff --git a/test/testfiles_for_unittests/obj_stabs.elf b/test/testfiles_for_unittests/obj_stabs.elf
new file mode 100644 (file)
index 0000000..8ee5422
Binary files /dev/null and b/test/testfiles_for_unittests/obj_stabs.elf differ