• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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