1#!/usr/bin/env python 2# 3# Copyright (C) 2018 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16# 17"""This file contains unit tests for elf_parser.""" 18 19import os 20import unittest 21 22from vts.utils.python.library import elf_parser as elf 23 24 25_SECTION_NAMES = {'test.rela', 'test.honeycomb', 'test.jellybean', 26 'test.nougat', 'test.oreo', 'test.pie', 'test.dup'} 27 28_EXPORTED_SYMBOLS = {'global_var_1', 'global_var_2', 29 '_Z15exported_func_1v', '_Z15exported_func_2v'} 30 31R_X86_64_GLOB_DAT = 6 32 33_RELOCATIONS = {(R_X86_64_GLOB_DAT, 'global_var_1', 0), 34 (R_X86_64_GLOB_DAT, 'global_var_2', 0)} 35 36_ANDROID_RELOCATIONS = [(0x200008, (1 << 32) | 1, 0), 37 (0x200010, (2 << 32) | 1, 0), 38 (0x200020, 8, 128), 39 (0x200030, 8, 136), 40 (0x200040, 8, 152), 41 (0x200050, 8, 184)] 42 43_RELR_RELOCATIONS = [(0x300000, 0), 44 (0x300000 + 2 * 8, 0), 45 (0x300000 + 60 * 8, 0), 46 (0x300000 + 64 * 8, 0), 47 (0x400000, 0)] 48 49_DEPENDENCIES = ['libc.so.6', 'libm.so.6'] 50 51 52class ElfParserTest(unittest.TestCase): 53 """Unit tests for ElfParser from elf_parser.""" 54 55 def setUp(self): 56 """Creates an ElfParser.""" 57 dir_path = os.path.dirname(os.path.realpath(__file__)) 58 self.elf_file_path = os.path.join(dir_path, 'elf', 'testing', 59 'libtest.so') 60 self.elf_file = elf.ElfParser(self.elf_file_path) 61 62 def tearDown(self): 63 """Closes the ElfParser.""" 64 self.elf_file.Close() 65 66 def testGetSectionName(self): 67 """Tests that GetSectionName parses section names correctly.""" 68 sh_names = [self.elf_file.GetSectionName(sh) 69 for sh in self.elf_file.Shdr] 70 self.assertFalse(_SECTION_NAMES.difference(sh_names)) 71 72 def testGetSectionsByName(self): 73 """Tests that GetSectionsByName finds all sections of the same name.""" 74 none_secs = list(self.elf_file.GetSectionsByName('no.such.section')) 75 dup_secs = list(self.elf_file.GetSectionsByName('test.dup')) 76 self.assertEqual(len(none_secs), 0) 77 self.assertEqual(len(dup_secs), 2) 78 79 def testGetSectionByName(self): 80 """Tests that GetSectionByName finds section by name correctly.""" 81 none_sec = self.elf_file.GetSectionByName('no.such.section') 82 self.assertEqual(none_sec, None) 83 for section_name in _SECTION_NAMES: 84 sh = self.elf_file.GetSectionByName(section_name) 85 self.assertIsNotNone(sh) 86 87 def testGetSymbols(self): 88 """Tests that GetSymbols parses symbol table correctly.""" 89 symtab = self.elf_file.GetSectionByName('.symtab') 90 strtab = self.elf_file.Shdr[symtab.sh_link] 91 syms = self.elf_file.GetSymbols(symtab) 92 sym_names = [self.elf_file.GetString(strtab, sym.st_name) 93 for sym in syms] 94 self.assertFalse(_EXPORTED_SYMBOLS.difference(sym_names)) 95 96 def testGetRelocations(self): 97 """Tests that GetRelocations parses relocation table correctly.""" 98 reltab = self.elf_file.GetSectionByName('.rela.dyn') 99 symtab = self.elf_file.Shdr[reltab.sh_link] 100 strtab = self.elf_file.Shdr[symtab.sh_link] 101 relocs = [] 102 for rela in self.elf_file.GetRelocations(reltab): 103 sym = self.elf_file.GetRelocationSymbol(symtab, rela) 104 sym_name = self.elf_file.GetString(strtab, sym.st_name) 105 relocs.append((rela.GetType(), sym_name, rela.r_addend)) 106 self.assertFalse(_RELOCATIONS.difference(relocs)) 107 108 def testGetRelocations_Android(self): 109 """Tests that GetRelocations parses Android packed format correctly.""" 110 android_rela = self.elf_file.GetSectionByName('test.rela') 111 relocs = [] 112 for rela in self.elf_file.GetRelocations(android_rela): 113 relocs.append((rela.r_offset, rela.r_info, rela.r_addend)) 114 self.assertEqual(relocs, _ANDROID_RELOCATIONS) 115 116 def testGetRelocations_Relr(self): 117 """Tests that GetRelocations parses RELR section correctly.""" 118 reltab = self.elf_file.GetSectionByName('.relr.dyn') 119 # It isn't actually a relocation section generated by linker. 120 reltab.sh_entsize = 8 121 relocs = [] 122 for rela in self.elf_file.GetRelocations(reltab): 123 relocs.append((rela.r_offset, rela.r_info)) 124 self.assertEqual(relocs, _RELR_RELOCATIONS) 125 126 def testIsExecutable(self): 127 """Tests that IsExecutable determines file type correctly.""" 128 is_executable = self.elf_file.IsExecutable() 129 self.assertFalse(is_executable) 130 131 def testIsSharedObject(self): 132 """Tests that IsSharedObject determines file type correctly.""" 133 is_shared_object = self.elf_file.IsSharedObject() 134 self.assertTrue(is_shared_object) 135 136 def testHasAndroidIdent(self): 137 """Tests that HasAndroidIdent finds .note.android.ident section.""" 138 has_android_ident = self.elf_file.HasAndroidIdent() 139 self.assertTrue(has_android_ident) 140 141 def testMatchCpuAbi(self): 142 """Tests that MatchCpuAbi determines machine type correctly.""" 143 self.assertTrue(self.elf_file.MatchCpuAbi("x86_64")) 144 self.assertFalse(self.elf_file.MatchCpuAbi("x86")) 145 146 def testListDependencies(self): 147 """Tests that ListDependencies lists ELF dependencies correctly.""" 148 deps = self.elf_file.ListDependencies() 149 self.assertEqual(deps, _DEPENDENCIES) 150 151 def testListGlobalSymbols(self): 152 """Tests that ListGlobalSymbols lists global symbols correctly.""" 153 syms = self.elf_file.ListGlobalSymbols(False, '.dynsym', '.dynstr') 154 self.assertFalse(_EXPORTED_SYMBOLS.difference(syms)) 155 156 def testGetProgramInterpreter(self): 157 """Tests that GetProgramInterpreter parses segment type correctly.""" 158 interp = self.elf_file.GetProgramInterpreter() 159 self.assertEqual(interp, "/lib64/ld-linux-x86-64.so.2") 160 161 162if __name__ == '__main__': 163 unittest.main() 164