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_RUNPATHS = ['/runpath1', '/runpath2'] 52 53 54class ElfParserTest(unittest.TestCase): 55 """Unit tests for ElfParser from elf_parser.""" 56 57 def setUp(self): 58 """Creates an ElfParser.""" 59 dir_path = os.path.dirname(os.path.realpath(__file__)) 60 self.elf_file_path = os.path.join(dir_path, 'elf', 'testing', 61 'libtest.so') 62 self.elf_file = elf.ElfParser(self.elf_file_path) 63 64 def tearDown(self): 65 """Closes the ElfParser.""" 66 self.elf_file.Close() 67 68 def testGetSectionName(self): 69 """Tests that GetSectionName parses section names correctly.""" 70 sh_names = [self.elf_file.GetSectionName(sh) 71 for sh in self.elf_file.Shdr] 72 self.assertFalse(_SECTION_NAMES.difference(sh_names)) 73 74 def testGetSectionsByName(self): 75 """Tests that GetSectionsByName finds all sections of the same name.""" 76 none_secs = list(self.elf_file.GetSectionsByName('no.such.section')) 77 dup_secs = list(self.elf_file.GetSectionsByName('test.dup')) 78 self.assertEqual(len(none_secs), 0) 79 self.assertEqual(len(dup_secs), 2) 80 81 def testGetSectionByName(self): 82 """Tests that GetSectionByName finds section by name correctly.""" 83 none_sec = self.elf_file.GetSectionByName('no.such.section') 84 self.assertEqual(none_sec, None) 85 for section_name in _SECTION_NAMES: 86 sh = self.elf_file.GetSectionByName(section_name) 87 self.assertIsNotNone(sh) 88 89 def testGetSymbols(self): 90 """Tests that GetSymbols parses symbol table correctly.""" 91 symtab = self.elf_file.GetSectionByName('.symtab') 92 strtab = self.elf_file.Shdr[symtab.sh_link] 93 syms = self.elf_file.GetSymbols(symtab) 94 sym_names = [self.elf_file.GetString(strtab, sym.st_name) 95 for sym in syms] 96 self.assertFalse(_EXPORTED_SYMBOLS.difference(sym_names)) 97 98 def testGetRelocations(self): 99 """Tests that GetRelocations parses relocation table correctly.""" 100 reltab = self.elf_file.GetSectionByName('.rela.dyn') 101 symtab = self.elf_file.Shdr[reltab.sh_link] 102 strtab = self.elf_file.Shdr[symtab.sh_link] 103 relocs = [] 104 for rela in self.elf_file.GetRelocations(reltab): 105 sym = self.elf_file.GetRelocationSymbol(symtab, rela) 106 sym_name = self.elf_file.GetString(strtab, sym.st_name) 107 relocs.append((rela.GetType(), sym_name, rela.r_addend)) 108 self.assertFalse(_RELOCATIONS.difference(relocs)) 109 110 def testGetRelocations_Android(self): 111 """Tests that GetRelocations parses Android packed format correctly.""" 112 android_rela = self.elf_file.GetSectionByName('test.rela') 113 relocs = [] 114 for rela in self.elf_file.GetRelocations(android_rela): 115 relocs.append((rela.r_offset, rela.r_info, rela.r_addend)) 116 self.assertEqual(relocs, _ANDROID_RELOCATIONS) 117 118 def testGetRelocations_Relr(self): 119 """Tests that GetRelocations parses RELR section correctly.""" 120 reltab = self.elf_file.GetSectionByName('.relr.dyn') 121 # It isn't actually a relocation section generated by linker. 122 reltab.sh_entsize = 8 123 relocs = [] 124 for rela in self.elf_file.GetRelocations(reltab): 125 relocs.append((rela.r_offset, rela.r_info)) 126 self.assertEqual(relocs, _RELR_RELOCATIONS) 127 128 def testIsExecutable(self): 129 """Tests that IsExecutable determines file type correctly.""" 130 is_executable = self.elf_file.IsExecutable() 131 self.assertFalse(is_executable) 132 133 def testIsSharedObject(self): 134 """Tests that IsSharedObject determines file type correctly.""" 135 is_shared_object = self.elf_file.IsSharedObject() 136 self.assertTrue(is_shared_object) 137 138 def testHasAndroidIdent(self): 139 """Tests that HasAndroidIdent finds .note.android.ident section.""" 140 has_android_ident = self.elf_file.HasAndroidIdent() 141 self.assertTrue(has_android_ident) 142 143 def testMatchCpuAbi(self): 144 """Tests that MatchCpuAbi determines machine type correctly.""" 145 self.assertTrue(self.elf_file.MatchCpuAbi("x86_64")) 146 self.assertFalse(self.elf_file.MatchCpuAbi("x86")) 147 148 def testListDependencies(self): 149 """Tests that ListDependencies lists ELF dependencies correctly.""" 150 deps, runpaths = self.elf_file.ListDependencies() 151 self.assertEqual(deps, _DEPENDENCIES) 152 self.assertEqual(runpaths, _RUNPATHS) 153 154 def testListGlobalSymbols(self): 155 """Tests that ListGlobalSymbols lists global symbols correctly.""" 156 syms = self.elf_file.ListGlobalSymbols(False, '.dynsym', '.dynstr') 157 self.assertFalse(_EXPORTED_SYMBOLS.difference(syms)) 158 159 def testGetProgramInterpreter(self): 160 """Tests that GetProgramInterpreter parses segment type correctly.""" 161 interp = self.elf_file.GetProgramInterpreter() 162 self.assertEqual(interp, "/lib64/ld-linux-x86-64.so.2") 163 164 165if __name__ == '__main__': 166 unittest.main() 167