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