1#!/usr/bin/env python3 2 3from __future__ import print_function 4 5import os 6import re 7import subprocess 8import sys 9import unittest 10 11from .compat import TemporaryDirectory, makedirs 12from .ndk_toolchain import create_targets 13 14 15SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) 16VNDK_DEF_TOOL = os.path.join(SCRIPT_DIR, '..', 'vndk_definition_tool.py') 17 18INPUT_DIR = os.path.join(SCRIPT_DIR, 'testdata', 'test_elfdump', 'input') 19EXPECTED_DIR = os.path.join(SCRIPT_DIR, 'testdata', 'test_elfdump', 'expected') 20test_dir_base = None 21 22 23def run_elf_dump(path): 24 cmd = [sys.executable, VNDK_DEF_TOOL, 'elfdump', path] 25 return subprocess.check_output(cmd, universal_newlines=True) 26 27 28class ELFDumpTest(unittest.TestCase): 29 @classmethod 30 def setUpClass(cls): 31 cls.targets = create_targets() 32 33 if test_dir_base: 34 cls.test_dir_base = test_dir_base 35 else: 36 cls.tmp_dir = TemporaryDirectory() 37 cls.test_dir_base = cls.tmp_dir.name 38 39 cls._build_fixtures(cls.target_name) 40 41 42 @classmethod 43 def tearDownClass(cls): 44 if not test_dir_base: 45 cls.tmp_dir.cleanup() 46 47 48 @classmethod 49 def _build_fixtures(cls, target_name): 50 target = cls.targets[target_name] 51 52 cls.expected_dir = os.path.join(EXPECTED_DIR, target_name) 53 cls.test_dir = os.path.join(cls.test_dir_base, target_name) 54 55 makedirs(cls.test_dir, exist_ok=True) 56 57 # Compile main.o. 58 src_file = os.path.join(INPUT_DIR, 'main.c') 59 obj_file = os.path.join(cls.test_dir, 'main.o') 60 target.compile(obj_file, src_file, []) 61 62 # Link main.out. 63 out_file = os.path.join(cls.test_dir, 'main.out') 64 target.link(out_file, [obj_file], ['-ldl', '-lc', '-lstdc++']) 65 66 # Compile test.o. 67 src_file = os.path.join(INPUT_DIR, 'test.c') 68 obj_file = os.path.join(cls.test_dir, 'test.o') 69 target.compile(obj_file, src_file, []) 70 71 # Link libtest.so. 72 out_file = os.path.join(cls.test_dir, 'libtest.so') 73 target.link(out_file, [obj_file], ['-shared', '-lc']) 74 75 # Link libtest-rpath.so. 76 out_file = os.path.join(cls.test_dir, 'libtest-rpath.so') 77 target.link(out_file, [obj_file], 78 ['-shared', '-lc', '-Wl,-rpath,$ORIGIN/../lib', 79 '-Wl,--disable-new-dtags']) 80 81 # Link libtest-rpath-multi.so. 82 out_file = os.path.join(cls.test_dir, 'libtest-rpath-multi.so') 83 target.link(out_file, [obj_file], 84 ['-shared', '-lc', '-Wl,-rpath,/system/lib:/vendor/lib', 85 '-Wl,--disable-new-dtags']) 86 87 # Link libtest-runpath.so. 88 out_file = os.path.join(cls.test_dir, 'libtest-runpath.so') 89 target.link(out_file, [obj_file], 90 ['-shared', '-lc', '-Wl,-rpath,$ORIGIN/../lib', 91 '-Wl,--enable-new-dtags']) 92 93 # Link libtest-runpath-multi.so. 94 out_file = os.path.join(cls.test_dir, 'libtest-runpath-multi.so') 95 target.link(out_file, [obj_file], 96 ['-shared', '-lc', '-Wl,-rpath,/system/lib:/vendor/lib', 97 '-Wl,--enable-new-dtags']) 98 99 100 def _remove_size_lines(self, lines): 101 """Remove file size information because they may vary.""" 102 prefixes = ( 103 'FILE_SIZE\t', 104 'RO_SEG_FILE_SIZE\t', 105 'RO_SEG_MEM_SIZE\t', 106 'RW_SEG_FILE_SIZE\t', 107 'RW_SEG_MEM_SIZE\t', 108 ) 109 patt = re.compile('|'.join('(?:' + re.escape(x) +')' for x in prefixes)) 110 return [line for line in lines if not patt.match(line)] 111 112 113 def _assert_equal_to_file(self, expected_file_name, actual): 114 actual = actual.splitlines(True) 115 expected_file_path = os.path.join(self.expected_dir, expected_file_name) 116 with open(expected_file_path, 'r') as f: 117 expected = f.readlines() 118 self.assertEqual(self._remove_size_lines(expected), 119 self._remove_size_lines(actual)) 120 121 122 def _test_main_out(self): 123 out_file = os.path.join(self.test_dir, 'main.out') 124 self._assert_equal_to_file('main.out.txt', run_elf_dump(out_file)) 125 126 127 def _test_libtest(self, expected_file_name, lib_name): 128 lib_file = os.path.join(self.test_dir, lib_name) 129 self._assert_equal_to_file(expected_file_name, run_elf_dump(lib_file)) 130 131 132def create_target_test(target_name): 133 def test_main(self): 134 self._test_main_out() 135 136 def test_libtest(self): 137 self._test_libtest('libtest.so.txt', 'libtest.so') 138 139 def test_libtest_rpath(self): 140 self._test_libtest('libtest-rpath.so.txt', 'libtest-rpath.so') 141 142 def test_libtest_rpath_multi(self): 143 self._test_libtest('libtest-rpath-multi.so.txt', 144 'libtest-rpath-multi.so') 145 146 def test_libtest_runpath(self): 147 self._test_libtest('libtest-runpath.so.txt', 'libtest-runpath.so') 148 149 def test_libtest_runpath_multi(self): 150 self._test_libtest('libtest-runpath-multi.so.txt', 151 'libtest-runpath-multi.so') 152 153 class_name = 'ELFDumpTest_' + target_name 154 globals()[class_name] = type( 155 class_name, (ELFDumpTest,), 156 dict(test_main=test_main, 157 test_libtest=test_libtest, 158 test_libtest_rpath=test_libtest_rpath, 159 test_libtest_rpath_multi=test_libtest_rpath_multi, 160 test_libtest_runpath=test_libtest_runpath, 161 test_libtest_runpath_multi=test_libtest_runpath_multi, 162 target_name=target_name)) 163 164 165for target in ('arm', 'arm64', 'mips', 'mips64', 'x86', 'x86_64'): 166 create_target_test(target) 167