From: Vasily E Date: Thu, 31 Jan 2019 14:17:14 +0000 (+0300) Subject: Fixup error on empty .debug_pubtypes section (#215) X-Git-Tag: v0.26~26 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=eeba82a4d41c2994eede5815abeb7ea78ac525e4;p=pyelftools.git Fixup error on empty .debug_pubtypes section (#215) * tox: explicitly set locale Locale affects GNU binutils output translation which cause run_readelf_tests.py to fail if system language is not English. Signed-off-by: Efimov Vasily * test: unittest reproducing error with empty ".debug_pubtypes" section Signed-off-by: Efimov Vasily * NameLUT: use `construct.If` to declare "name" field This patch also fixes problem with empty first entry. Signed-off-by: Efimov Vasily * NameLUT._get_entries: remove unused `bytes_read` Signed-off-by: Efimov Vasily --- diff --git a/elftools/dwarf/namelut.py b/elftools/dwarf/namelut.py index b7de798..d24a5de 100755 --- a/elftools/dwarf/namelut.py +++ b/elftools/dwarf/namelut.py @@ -12,7 +12,7 @@ from collections import OrderedDict from ..common.utils import struct_parse from bisect import bisect_right import math -from ..construct import CString, Struct +from ..construct import CString, Struct, If NameLUTEntry = collections.namedtuple('NameLUTEntry', 'cu_ofs die_ofs') @@ -158,11 +158,14 @@ class NameLUT(collections.Mapping): entries = OrderedDict() cu_headers = [] offset = 0 + # According to 6.1.1. of DWARFv4, each set of names is terminated by + # an offset field containing zero (and no following string). Because + # of sequential parsing, every next entry may be that terminator. + # So, field "name" is conditional. entry_struct = Struct("Dwarf_offset_name_pair", self._structs.Dwarf_offset('die_ofs'), - CString('name')) - die_ofs_struct = self._structs.Dwarf_offset('die_ofs') - + If(lambda ctx: ctx['die_ofs'],CString('name'))) + # each run of this loop will fetch one CU worth of entries. while offset < self._size: @@ -174,29 +177,21 @@ class NameLUT(collections.Mapping): offset = (offset + namelut_hdr.unit_length + self._structs.initial_length_field_size()) - bytes_read = 0 # before inner loop, latch data that will be used in the inner # loop to avoid attribute access and other computation. hdr_cu_ofs = namelut_hdr.debug_info_offset - # read the first tuple for this CU. - entry = struct_parse(entry_struct, - self._stream) + # while die_ofs of the entry is non-zero (which indicates the end) ... while True: + entry = struct_parse(entry_struct, self._stream) + + # if it is zero, then we done. + if entry.die_ofs == 0: + break # add this entry to the look-up dictionary. entries[entry.name.decode('utf-8')] = NameLUTEntry( cu_ofs = hdr_cu_ofs, die_ofs = hdr_cu_ofs + entry.die_ofs) - # get the DIE offset entry alone. - die_ofs = struct_parse(die_ofs_struct, self._stream) - # if it is zero, then we done. - if die_ofs == 0: - break - else: - # else this is a valid DIE, get the name as well and - # construct the entry - entry.name = struct_parse(CString('name'), self._stream) - entry.die_ofs = die_ofs # return the entries parsed so far. return (entries, cu_headers) diff --git a/test/test_pubtypes.py b/test/test_pubtypes.py new file mode 100644 index 0000000..a0eb642 --- /dev/null +++ b/test/test_pubtypes.py @@ -0,0 +1,25 @@ +#------------------------------------------------------------------------------- +# elftools tests +# +# Efimov Vasiliy (real@ispras.ru) +# This code is in the public domain +#------------------------------------------------------------------------------- +import os +import unittest + +from elftools.elf.elffile import ELFFile + + +class TestEmptyPubtypes(unittest.TestCase): + def test_empty_pubtypes(self): + test_dir = os.path.join('test', 'testfiles_for_unittests') + with open(os.path.join(test_dir, 'empty_pubtypes', 'main'), 'rb') as f: + elf = ELFFile(f) + + # This test targets `ELFParseError` caused by buggy handling + # of ".debug_pubtypes" section which only has zero terminator + # entry. + self.assertEqual(len(elf.get_dwarf_info().get_pubtypes()), 0) + +if __name__ == '__main__': + unittest.main() diff --git a/test/testfiles_for_unittests/empty_pubtypes/Makefile b/test/testfiles_for_unittests/empty_pubtypes/Makefile new file mode 100644 index 0000000..20decd4 --- /dev/null +++ b/test/testfiles_for_unittests/empty_pubtypes/Makefile @@ -0,0 +1,2 @@ +main: +main: CFLAGS=-gpubnames -g -O0 diff --git a/test/testfiles_for_unittests/empty_pubtypes/main b/test/testfiles_for_unittests/empty_pubtypes/main new file mode 100755 index 0000000..fc6c9b3 Binary files /dev/null and b/test/testfiles_for_unittests/empty_pubtypes/main differ diff --git a/test/testfiles_for_unittests/empty_pubtypes/main.c b/test/testfiles_for_unittests/empty_pubtypes/main.c new file mode 100644 index 0000000..ab73b3a --- /dev/null +++ b/test/testfiles_for_unittests/empty_pubtypes/main.c @@ -0,0 +1 @@ +void main() {} diff --git a/tox.ini b/tox.ini index 7e9b484..461a248 100644 --- a/tox.ini +++ b/tox.ini @@ -2,6 +2,8 @@ envlist = py27,py34,py35 [testenv] +setenv = + LC_ALL = en_US commands = python test/run_all_unittests.py python test/run_examples_test.py