#!/usr/bin/env python3 from __future__ import print_function import tempfile import unittest from vndk_definition_tool import Elf_Sym, ELF from .compat import StringIO class ElfSymTest(unittest.TestCase): def setUp(self): self.sym_local = Elf_Sym(0, 0, 4, 0, 0, 1) self.sym_global = Elf_Sym(0, 0, 4, 17, 0, 1) self.sym_weak = Elf_Sym(0, 0, 4, 33, 0, 1) self.sym_undef = Elf_Sym(0, 0, 4, 16, 0, 0) def test_is_local(self): self.assertTrue(self.sym_local.is_local) self.assertFalse(self.sym_global.is_local) self.assertFalse(self.sym_weak.is_local) def test_is_global(self): self.assertFalse(self.sym_local.is_global) self.assertTrue(self.sym_global.is_global) self.assertFalse(self.sym_weak.is_global) def test_is_weak(self): self.assertFalse(self.sym_local.is_weak) self.assertFalse(self.sym_global.is_weak) self.assertTrue(self.sym_weak.is_weak) def test_is_undef(self): self.assertFalse(self.sym_global.is_undef) self.assertTrue(self.sym_undef.is_undef) 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))) elf = ELF(ei_class=ELF.ELFCLASS32, ei_data=ELF.ELFDATA2LSB, e_machine=183, dt_rpath=['a'], dt_runpath=['b'], dt_needed=['c', 'd'], exported_symbols={'e', 'f', 'g'}) self.assertEqual(elf, eval(repr(elf))) def test_class_name(self): self.assertEqual('None', ELF().elf_class_name) elf = ELF(ELF.ELFCLASS32) self.assertEqual('32', elf.elf_class_name) self.assertTrue(elf.is_32bit) self.assertFalse(elf.is_64bit) elf = ELF(ELF.ELFCLASS64) self.assertEqual('64', elf.elf_class_name) self.assertFalse(elf.is_32bit) self.assertTrue(elf.is_64bit) def test_endianness(self): self.assertEqual('None', ELF().elf_data_name) self.assertEqual('Little-Endian', ELF(None, ELF.ELFDATA2LSB).elf_data_name) self.assertEqual('Big-Endian', ELF(None, ELF.ELFDATA2MSB).elf_data_name) def test_machine_name(self): self.assertEqual('EM_NONE', ELF(e_machine=0).elf_machine_name) self.assertEqual('EM_386', ELF(e_machine=3).elf_machine_name) self.assertEqual('EM_MIPS', ELF(e_machine=8).elf_machine_name) self.assertEqual('EM_ARM', ELF(e_machine=40).elf_machine_name) self.assertEqual('EM_X86_64', ELF(e_machine=62).elf_machine_name) self.assertEqual('EM_AARCH64', ELF(e_machine=183).elf_machine_name) def test_dt_rpath_runpath(self): elf = ELF() self.assertEqual([], elf.dt_rpath) self.assertEqual([], elf.dt_runpath) elf = ELF(None, None, 0, ['a'], ['b']) self.assertEqual(['a'], elf.dt_rpath) self.assertEqual(['b'], elf.dt_runpath) def test_dump(self): elf = ELF(ELF.ELFCLASS32, ELF.ELFDATA2LSB, 183, ['a'], ['b'], ['libc.so', 'libm.so'], {'hello', 'world'}, {'d', 'e'}) f = StringIO() elf.dump(f) actual_output = f.getvalue() self.assertEqual('EI_CLASS\t32\n' 'EI_DATA\t\tLittle-Endian\n' 'E_MACHINE\tEM_AARCH64\n' 'FILE_SIZE\t0\n' 'RO_SEG_FILE_SIZE\t0\n' 'RO_SEG_MEM_SIZE\t0\n' 'RW_SEG_FILE_SIZE\t0\n' 'RW_SEG_MEM_SIZE\t0\n' 'DT_RPATH\ta\n' 'DT_RUNPATH\tb\n' 'DT_NEEDED\tlibc.so\n' 'DT_NEEDED\tlibm.so\n' 'EXP_SYMBOL\thello\n' 'EXP_SYMBOL\tworld\n' 'IMP_SYMBOL\td\n' 'IMP_SYMBOL\te\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' 'FILE_SIZE\t90\n' 'RO_SEG_FILE_SIZE\t18\n' 'RO_SEG_MEM_SIZE\t24\n' 'RW_SEG_FILE_SIZE\t42\n' 'RW_SEG_MEM_SIZE\t81\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(90, res.file_size) self.assertEqual(18, res.ro_seg_file_size) self.assertEqual(24, res.ro_seg_mem_size) self.assertEqual(42, res.rw_seg_file_size) self.assertEqual(81, res.rw_seg_mem_size) 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)) class ELFJniLibTest(unittest.TestCase): def test_lib_deps(self): elf = ELF(dt_needed=['libnativehelper.so']) self.assertTrue(elf.is_jni_lib()) elf = ELF(dt_needed=['libandroid_runtime.so']) self.assertTrue(elf.is_jni_lib()) elf = ELF(dt_needed=['libc.so']) self.assertFalse(elf.is_jni_lib()) def test_jni_symbols(self): elf = ELF(imported_symbols={'JNI_CreateJavaVM'}) self.assertTrue(elf.is_jni_lib()) elf = ELF(exported_symbols={'JNI_CreateJavaVM'}) self.assertTrue(elf.is_jni_lib()) elf = ELF(imported_symbols={'Java_com_example_Example_test'}) self.assertTrue(elf.is_jni_lib()) elf = ELF(exported_symbols={'Java_com_example_Example_test'}) self.assertTrue(elf.is_jni_lib()) elf = ELF(imported_symbols={'printf'}) self.assertFalse(elf.is_jni_lib()) elf = ELF(exported_symbols={'printf'}) self.assertFalse(elf.is_jni_lib())