From d65ab038fa662f0d588f881a0733f365c43f365d Mon Sep 17 00:00:00 2001 From: PromyLOPh Date: Sat, 25 Feb 2017 16:50:52 +0100 Subject: [PATCH] Add .stab section parser (#137) * Add .stab section parser * Replace tabs with spaces * Add unit test for stabs parser --- elftools/elf/elffile.py | 5 ++- elftools/elf/sections.py | 25 ++++++++++++++ elftools/elf/structs.py | 12 +++++++ test/test_stab.py | 38 +++++++++++++++++++++ test/testfiles_for_unittests/obj_stabs.S | 3 ++ test/testfiles_for_unittests/obj_stabs.elf | Bin 0 -> 920 bytes 6 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 test/test_stab.py create mode 100644 test/testfiles_for_unittests/obj_stabs.S create mode 100644 test/testfiles_for_unittests/obj_stabs.elf diff --git a/elftools/elf/elffile.py b/elftools/elf/elffile.py index 64fd479..20e070d 100644 --- a/elftools/elf/elffile.py +++ b/elftools/elf/elffile.py @@ -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) diff --git a/elftools/elf/sections.py b/elftools/elf/sections.py index 1bc1715..c772958 100644 --- a/elftools/elf/sections.py +++ b/elftools/elf/sections.py @@ -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 + diff --git a/elftools/elf/structs.py b/elftools/elf/structs.py index d2404ab..8cbeb5c 100644 --- a/elftools/elf/structs.py +++ b/elftools/elf/structs.py @@ -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 index 0000000..83067b8 --- /dev/null +++ b/test/test_stab.py @@ -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 index 0000000..ecdc5b4 --- /dev/null +++ b/test/testfiles_for_unittests/obj_stabs.S @@ -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 index 0000000000000000000000000000000000000000..8ee5422e6a9ca415cb780472a69ab2860bb7f505 GIT binary patch literal 920 zcmb<-^>JfjWMqH=Mg}_u1P><4zz~5X=l~XWVBln6gQ{g>Py~wc0`b%nMGo)xt-U7< zWILv9{JC$}zf%nPNm=p5C5cJJdch1iiAkwB42gO9B^jwj3J@NHUU6kEP##E^6hY_= z7^@_;qJ%*&C9x!tK`*Je7^DQE5NKRU5!fZT2xhE4VPIfpV8W_}87PAdFf*`V69%eg z#VSq>L1~~Npde>MGt2>v591<54_F8kA0RPwA31OdtNKuoTF9iU!xGeNdG zfCwN^fl%-egoUsORNM$iquULVN`cCQ{D%zC?Ggk^V$B?qAT gCO~OW7=hvlM1z0?gaYOb?DhvhEy89WR4bSQ0EMwJuK)l5 literal 0 HcmV?d00001 -- 2.30.2