1#!/usr/bin/env python3
2
3from __future__ import print_function
4
5import os
6import sys
7sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
8
9import tempfile
10import unittest
11
12from compat import StringIO
13from vndk_definition_tool import Elf_Sym, ELF
14
15class ElfSymTest(unittest.TestCase):
16    def setUp(self):
17        self.sym_local = Elf_Sym(0, 0, 4, 0, 0, 1)
18        self.sym_global = Elf_Sym(0, 0, 4, 17, 0, 1)
19        self.sym_weak = Elf_Sym(0, 0, 4, 33, 0, 1)
20        self.sym_undef = Elf_Sym(0, 0, 4, 16, 0, 0)
21
22    def test_is_local(self):
23        self.assertTrue(self.sym_local.is_local)
24        self.assertFalse(self.sym_global.is_local)
25        self.assertFalse(self.sym_weak.is_local)
26
27    def test_is_global(self):
28        self.assertFalse(self.sym_local.is_global)
29        self.assertTrue(self.sym_global.is_global)
30        self.assertFalse(self.sym_weak.is_global)
31
32    def test_is_weak(self):
33        self.assertFalse(self.sym_local.is_weak)
34        self.assertFalse(self.sym_global.is_weak)
35        self.assertTrue(self.sym_weak.is_weak)
36
37    def test_is_undef(self):
38        self.assertFalse(self.sym_global.is_undef)
39        self.assertTrue(self.sym_undef.is_undef)
40
41
42class ELFTest(unittest.TestCase):
43    def test_get_ei_class_from_name(self):
44        self.assertEqual(ELF.ELFCLASS32, ELF.get_ei_class_from_name('32'))
45        self.assertEqual(ELF.ELFCLASS64, ELF.get_ei_class_from_name('64'))
46
47    def test_get_ei_data_from_name(self):
48        self.assertEqual(ELF.ELFDATA2LSB,
49                         ELF.get_ei_data_from_name('Little-Endian'))
50        self.assertEqual(ELF.ELFDATA2MSB,
51                         ELF.get_ei_data_from_name('Big-Endian'))
52
53    def test_get_e_machine_from_name(self):
54        self.assertEqual(0, ELF.get_e_machine_from_name('EM_NONE'))
55        self.assertEqual(3, ELF.get_e_machine_from_name('EM_386'))
56        self.assertEqual(8, ELF.get_e_machine_from_name('EM_MIPS'))
57        self.assertEqual(40, ELF.get_e_machine_from_name('EM_ARM'))
58        self.assertEqual(62, ELF.get_e_machine_from_name('EM_X86_64'))
59        self.assertEqual(183, ELF.get_e_machine_from_name('EM_AARCH64'))
60
61    def test_repr(self):
62        elf = ELF()
63        self.assertEqual(elf, eval(repr(elf)))
64
65        elf = ELF(ei_class=ELF.ELFCLASS32, ei_data=ELF.ELFDATA2LSB,
66                  e_machine=183, dt_rpath=['a'], dt_runpath=['b'],
67                  dt_needed=['c', 'd'], exported_symbols={'e', 'f', 'g'})
68        self.assertEqual(elf, eval(repr(elf)))
69
70    def test_class_name(self):
71        self.assertEqual('None', ELF().elf_class_name)
72
73        elf = ELF(ELF.ELFCLASS32)
74        self.assertEqual('32', elf.elf_class_name)
75        self.assertTrue(elf.is_32bit)
76        self.assertFalse(elf.is_64bit)
77
78        elf = ELF(ELF.ELFCLASS64)
79        self.assertEqual('64', elf.elf_class_name)
80        self.assertFalse(elf.is_32bit)
81        self.assertTrue(elf.is_64bit)
82
83    def test_endianness(self):
84        self.assertEqual('None', ELF().elf_data_name)
85        self.assertEqual('Little-Endian',
86                         ELF(None, ELF.ELFDATA2LSB).elf_data_name)
87        self.assertEqual('Big-Endian',
88                         ELF(None, ELF.ELFDATA2MSB).elf_data_name)
89
90    def test_machine_name(self):
91        self.assertEqual('EM_NONE', ELF(e_machine=0).elf_machine_name)
92        self.assertEqual('EM_386', ELF(e_machine=3).elf_machine_name)
93        self.assertEqual('EM_MIPS', ELF(e_machine=8).elf_machine_name)
94        self.assertEqual('EM_ARM', ELF(e_machine=40).elf_machine_name)
95        self.assertEqual('EM_X86_64', ELF(e_machine=62).elf_machine_name)
96        self.assertEqual('EM_AARCH64', ELF(e_machine=183).elf_machine_name)
97
98    def test_dt_rpath_runpath(self):
99        elf = ELF()
100        self.assertEqual([], elf.dt_rpath)
101        self.assertEqual([], elf.dt_runpath)
102
103        elf = ELF(None, None, 0, ['a'], ['b'])
104        self.assertEqual(['a'], elf.dt_rpath)
105        self.assertEqual(['b'], elf.dt_runpath)
106
107    def test_dump(self):
108        elf = ELF(ELF.ELFCLASS32, ELF.ELFDATA2LSB, 183, ['a'], ['b'],
109                  ['libc.so', 'libm.so'], {'hello', 'world'}, {'d', 'e'})
110
111        f = StringIO()
112        elf.dump(f)
113        actual_output = f.getvalue()
114
115        self.assertEqual('EI_CLASS\t32\n'
116                         'EI_DATA\t\tLittle-Endian\n'
117                         'E_MACHINE\tEM_AARCH64\n'
118                         'FILE_SIZE\t0\n'
119                         'RO_SEG_FILE_SIZE\t0\n'
120                         'RO_SEG_MEM_SIZE\t0\n'
121                         'RW_SEG_FILE_SIZE\t0\n'
122                         'RW_SEG_MEM_SIZE\t0\n'
123                         'DT_RPATH\ta\n'
124                         'DT_RUNPATH\tb\n'
125                         'DT_NEEDED\tlibc.so\n'
126                         'DT_NEEDED\tlibm.so\n'
127                         'EXP_SYMBOL\thello\n'
128                         'EXP_SYMBOL\tworld\n'
129                         'IMP_SYMBOL\td\n'
130                         'IMP_SYMBOL\te\n',
131                         actual_output)
132
133    def test_parse_dump_file(self):
134        data = ('EI_CLASS\t64\n'
135                'EI_DATA\t\tLittle-Endian\n'
136                'E_MACHINE\tEM_AARCH64\n'
137                'FILE_SIZE\t90\n'
138                'RO_SEG_FILE_SIZE\t18\n'
139                'RO_SEG_MEM_SIZE\t24\n'
140                'RW_SEG_FILE_SIZE\t42\n'
141                'RW_SEG_MEM_SIZE\t81\n'
142                'DT_RPATH\trpath_1\n'
143                'DT_RPATH\trpath_2\n'
144                'DT_RUNPATH\trunpath_1\n'
145                'DT_RUNPATH\trunpath_2\n'
146                'DT_NEEDED\tlibc.so\n'
147                'DT_NEEDED\tlibm.so\n'
148                'EXP_SYMBOL\texported_1\n'
149                'EXP_SYMBOL\texported_2\n'
150                'IMP_SYMBOL\timported_1\n'
151                'IMP_SYMBOL\timported_2\n')
152
153        def check_parse_dump_file_result(res):
154            self.assertEqual(ELF.ELFCLASS64, res.ei_class)
155            self.assertEqual(ELF.ELFDATA2LSB, res.ei_data)
156            self.assertEqual(183, res.e_machine)
157            self.assertEqual(90, res.file_size)
158            self.assertEqual(18, res.ro_seg_file_size)
159            self.assertEqual(24, res.ro_seg_mem_size)
160            self.assertEqual(42, res.rw_seg_file_size)
161            self.assertEqual(81, res.rw_seg_mem_size)
162            self.assertEqual(['rpath_1', 'rpath_2'], res.dt_rpath)
163            self.assertEqual(['runpath_1', 'runpath_2'], res.dt_runpath)
164            self.assertEqual(['libc.so', 'libm.so'], res.dt_needed)
165            self.assertSetEqual({'exported_1', 'exported_2'},
166                                res.exported_symbols)
167            self.assertSetEqual({'imported_1', 'imported_2'},
168                                res.imported_symbols)
169
170        # Parse ELF dump from the string buffer.
171        check_parse_dump_file_result(ELF.load_dumps(data))
172
173        # Parse ELF dump from the given file path.
174        with tempfile.NamedTemporaryFile('w+') as f:
175            f.write(data)
176            f.flush()
177            f.seek(0)
178
179            check_parse_dump_file_result(ELF.load_dump(f.name))
180
181
182class ELFJniLibTest(unittest.TestCase):
183    def test_lib_deps(self):
184        elf = ELF(dt_needed=['libnativehelper.so'])
185        self.assertTrue(elf.is_jni_lib())
186
187        elf = ELF(dt_needed=['libandroid_runtime.so'])
188        self.assertTrue(elf.is_jni_lib())
189
190        elf = ELF(dt_needed=['libc.so'])
191        self.assertFalse(elf.is_jni_lib())
192
193    def test_jni_symbols(self):
194        elf = ELF(imported_symbols={'JNI_CreateJavaVM'})
195        self.assertTrue(elf.is_jni_lib())
196
197        elf = ELF(exported_symbols={'JNI_CreateJavaVM'})
198        self.assertTrue(elf.is_jni_lib())
199
200        elf = ELF(imported_symbols={'Java_com_example_Example_test'})
201        self.assertTrue(elf.is_jni_lib())
202
203        elf = ELF(exported_symbols={'Java_com_example_Example_test'})
204        self.assertTrue(elf.is_jni_lib())
205
206        elf = ELF(imported_symbols={'printf'})
207        self.assertFalse(elf.is_jni_lib())
208
209        elf = ELF(exported_symbols={'printf'})
210        self.assertFalse(elf.is_jni_lib())
211
212
213if __name__ == '__main__':
214    unittest.main()
215