vndk-def: Add parse from ELF dump file.

Test: ./tests/test_elf.py
Change-Id: Icff8aeeb395c201261ed53f421d714edb28dba5d
This commit is contained in:
Logan Chien
2017-03-07 08:42:22 +08:00
parent d2fcbb48bc
commit a43f141da1
2 changed files with 133 additions and 0 deletions

View File

@@ -6,6 +6,7 @@ import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import tempfile
import unittest
from compat import StringIO
@@ -39,6 +40,24 @@ class ElfSymTest(unittest.TestCase):
class ELFTest(unittest.TestCase):
def test_get_ei_class_from_name(self):
self.assertEqual(ELF.ELFCLASS32, ELF.get_ei_class_from_name('32'))
self.assertEqual(ELF.ELFCLASS64, ELF.get_ei_class_from_name('64'))
def test_get_ei_data_from_name(self):
self.assertEqual(ELF.ELFDATA2LSB,
ELF.get_ei_data_from_name('Little-Endian'))
self.assertEqual(ELF.ELFDATA2MSB,
ELF.get_ei_data_from_name('Big-Endian'))
def test_get_e_machine_from_name(self):
self.assertEqual(0, ELF.get_e_machine_from_name('EM_NONE'))
self.assertEqual(3, ELF.get_e_machine_from_name('EM_386'))
self.assertEqual(8, ELF.get_e_machine_from_name('EM_MIPS'))
self.assertEqual(40, ELF.get_e_machine_from_name('EM_ARM'))
self.assertEqual(62, ELF.get_e_machine_from_name('EM_X86_64'))
self.assertEqual(183, ELF.get_e_machine_from_name('EM_AARCH64'))
def test_repr(self):
elf = ELF()
self.assertEqual(elf, eval(repr(elf)))
@@ -116,5 +135,44 @@ class ELFTest(unittest.TestCase):
self.assertEqual('hello\nworld\n', actual_output)
def test_parse_dump_file(self):
data = ('EI_CLASS\t64\n'
'EI_DATA\t\tLittle-Endian\n'
'E_MACHINE\tEM_AARCH64\n'
'DT_RPATH\trpath_1\n'
'DT_RPATH\trpath_2\n'
'DT_RUNPATH\trunpath_1\n'
'DT_RUNPATH\trunpath_2\n'
'DT_NEEDED\tlibc.so\n'
'DT_NEEDED\tlibm.so\n'
'EXP_SYMBOL\texported_1\n'
'EXP_SYMBOL\texported_2\n'
'IMP_SYMBOL\timported_1\n'
'IMP_SYMBOL\timported_2\n')
def check_parse_dump_file_result(res):
self.assertEqual(ELF.ELFCLASS64, res.ei_class)
self.assertEqual(ELF.ELFDATA2LSB, res.ei_data)
self.assertEqual(183, res.e_machine)
self.assertEqual(['rpath_1', 'rpath_2'], res.dt_rpath)
self.assertEqual(['runpath_1', 'runpath_2'], res.dt_runpath)
self.assertEqual(['libc.so', 'libm.so'], res.dt_needed)
self.assertSetEqual({'exported_1', 'exported_2'},
res.exported_symbols)
self.assertSetEqual({'imported_1', 'imported_2'},
res.imported_symbols)
# Parse ELF dump from the string buffer.
check_parse_dump_file_result(ELF.load_dumps(data))
# Parse ELF dump from the given file path.
with tempfile.NamedTemporaryFile('w+') as f:
f.write(data)
f.flush()
f.seek(0)
check_parse_dump_file_result(ELF.load_dump(f.name))
if __name__ == '__main__':
unittest.main()

View File

@@ -141,6 +141,26 @@ class ELF(object):
}
@staticmethod
def _dict_find_key_by_value(d, dst):
for key, value in d.items():
if value == dst:
return key
raise KeyError(dst)
@staticmethod
def get_ei_class_from_name(name):
return ELF._dict_find_key_by_value(ELF._ELF_CLASS_NAMES, name)
@staticmethod
def get_ei_data_from_name(name):
return ELF._dict_find_key_by_value(ELF._ELF_DATA_NAMES, name)
@staticmethod
def get_e_machine_from_name(name):
return ELF._dict_find_key_by_value(ELF._ELF_MACHINE_IDS, name)
__slots__ = ('ei_class', 'ei_data', 'e_machine', 'dt_rpath', 'dt_runpath',
'dt_needed', 'exported_symbols', 'imported_symbols',)
@@ -388,6 +408,47 @@ class ELF(object):
with mmap(f.fileno(), st.st_size, access=ACCESS_READ) as image:
self._parse_from_buf(image)
def _parse_from_dump_lines(self, path, lines):
patt = re.compile('^([A-Za-z_]+)\t+(.*)$')
for line_no, line in enumerate(lines):
match = patt.match(line)
if not match:
print('error: {}: {}: failed to parse'
.format(path, line_no + 1), file=sys.stderr)
continue
key = match.group(1)
value = match.group(2)
if key == 'EI_CLASS':
self.ei_class = ELF.get_ei_class_from_name(value)
elif key == 'EI_DATA':
self.ei_data = ELF.get_ei_data_from_name(value)
elif key == 'E_MACHINE':
self.e_machine = ELF.get_e_machine_from_name(value)
elif key == 'DT_RPATH':
self.dt_rpath.append(intern(value))
elif key == 'DT_RUNPATH':
self.dt_runpath.append(intern(value))
elif key == 'DT_NEEDED':
self.dt_needed.append(intern(value))
elif key == 'EXP_SYMBOL':
self.exported_symbols.add(intern(value))
elif key == 'IMP_SYMBOL':
self.imported_symbols.add(intern(value))
else:
print('error: {}: {}: unknown tag name: {}'
.format(path, line_no + 1, key), file=sys.stderr)
def _parse_from_dump_file(self, path):
"""Load information from ELF dump file."""
with open(path, 'r') as f:
self._parse_from_dump_lines(path, f)
def _parse_from_dump_buf(self, buf):
"""Load information from ELF dump buffer."""
self._parse_from_dump_lines('<str:0x{:x}>'.format(id(buf)),
buf.splitlines())
@staticmethod
def load(path):
"""Create an ELF instance from the file path"""
@@ -402,6 +463,20 @@ class ELF(object):
elf._parse_from_buf(buf)
return elf
@staticmethod
def load_dump(path):
"""Create an ELF instance from a dump file path"""
elf = ELF()
elf._parse_from_dump_file(path)
return elf
@staticmethod
def load_dumps(buf):
"""Create an ELF instance from a dump file buffer"""
elf = ELF()
elf._parse_from_dump_buf(buf)
return elf
#------------------------------------------------------------------------------
# NDK and Banned Libraries