Merge tag 'u-boot-rockchip-20200501' of https://gitlab.denx.de/u-boot/custodians...
[platform/kernel/u-boot.git] / tools / binman / elf_test.py
1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright (c) 2017 Google, Inc
3 # Written by Simon Glass <sjg@chromium.org>
4 #
5 # Test for the elf module
6
7 import os
8 import shutil
9 import sys
10 import tempfile
11 import unittest
12
13 from binman import elf
14 from patman import command
15 from patman import test_util
16 from patman import tools
17 from patman import tout
18
19 binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
20
21
22 class FakeEntry:
23     """A fake Entry object, usedfor testing
24
25     This supports an entry with a given size.
26     """
27     def __init__(self, contents_size):
28         self.contents_size = contents_size
29         self.data = tools.GetBytes(ord('a'), contents_size)
30
31     def GetPath(self):
32         return 'entry_path'
33
34
35 class FakeSection:
36     """A fake Section object, used for testing
37
38     This has the minimum feature set needed to support testing elf functions.
39     A LookupSymbol() function is provided which returns a fake value for amu
40     symbol requested.
41     """
42     def __init__(self, sym_value=1):
43         self.sym_value = sym_value
44
45     def GetPath(self):
46         return 'section_path'
47
48     def LookupSymbol(self, name, weak, msg, base_addr):
49         """Fake implementation which returns the same value for all symbols"""
50         return self.sym_value
51
52
53 def BuildElfTestFiles(target_dir):
54     """Build ELF files used for testing in binman
55
56     This compiles and links the test files into the specified directory. It the
57     Makefile and source files in the binman test/ directory.
58
59     Args:
60         target_dir: Directory to put the files into
61     """
62     if not os.path.exists(target_dir):
63         os.mkdir(target_dir)
64     testdir = os.path.join(binman_dir, 'test')
65
66     # If binman is involved from the main U-Boot Makefile the -r and -R
67     # flags are set in MAKEFLAGS. This prevents this Makefile from working
68     # correctly. So drop any make flags here.
69     if 'MAKEFLAGS' in os.environ:
70         del os.environ['MAKEFLAGS']
71     tools.Run('make', '-C', target_dir, '-f',
72               os.path.join(testdir, 'Makefile'), 'SRC=%s/' % testdir)
73
74
75 class TestElf(unittest.TestCase):
76     @classmethod
77     def setUpClass(cls):
78         cls._indir = tempfile.mkdtemp(prefix='elf.')
79         tools.SetInputDirs(['.'])
80         BuildElfTestFiles(cls._indir)
81
82     @classmethod
83     def tearDownClass(cls):
84         if cls._indir:
85             shutil.rmtree(cls._indir)
86
87     @classmethod
88     def ElfTestFile(cls, fname):
89         return os.path.join(cls._indir, fname)
90
91     def testAllSymbols(self):
92         """Test that we can obtain a symbol from the ELF file"""
93         fname = self.ElfTestFile('u_boot_ucode_ptr')
94         syms = elf.GetSymbols(fname, [])
95         self.assertIn('.ucode', syms)
96
97     def testRegexSymbols(self):
98         """Test that we can obtain from the ELF file by regular expression"""
99         fname = self.ElfTestFile('u_boot_ucode_ptr')
100         syms = elf.GetSymbols(fname, ['ucode'])
101         self.assertIn('.ucode', syms)
102         syms = elf.GetSymbols(fname, ['missing'])
103         self.assertNotIn('.ucode', syms)
104         syms = elf.GetSymbols(fname, ['missing', 'ucode'])
105         self.assertIn('.ucode', syms)
106
107     def testMissingFile(self):
108         """Test that a missing file is detected"""
109         entry = FakeEntry(10)
110         section = FakeSection()
111         with self.assertRaises(ValueError) as e:
112             syms = elf.LookupAndWriteSymbols('missing-file', entry, section)
113         self.assertIn("Filename 'missing-file' not found in input path",
114                       str(e.exception))
115
116     def testOutsideFile(self):
117         """Test a symbol which extends outside the entry area is detected"""
118         entry = FakeEntry(10)
119         section = FakeSection()
120         elf_fname = self.ElfTestFile('u_boot_binman_syms')
121         with self.assertRaises(ValueError) as e:
122             syms = elf.LookupAndWriteSymbols(elf_fname, entry, section)
123         self.assertIn('entry_path has offset 4 (size 8) but the contents size '
124                       'is a', str(e.exception))
125
126     def testMissingImageStart(self):
127         """Test that we detect a missing __image_copy_start symbol
128
129         This is needed to mark the start of the image. Without it we cannot
130         locate the offset of a binman symbol within the image.
131         """
132         entry = FakeEntry(10)
133         section = FakeSection()
134         elf_fname = self.ElfTestFile('u_boot_binman_syms_bad')
135         self.assertEqual(elf.LookupAndWriteSymbols(elf_fname, entry, section),
136                          None)
137
138     def testBadSymbolSize(self):
139         """Test that an attempt to use an 8-bit symbol are detected
140
141         Only 32 and 64 bits are supported, since we need to store an offset
142         into the image.
143         """
144         entry = FakeEntry(10)
145         section = FakeSection()
146         elf_fname =self.ElfTestFile('u_boot_binman_syms_size')
147         with self.assertRaises(ValueError) as e:
148             syms = elf.LookupAndWriteSymbols(elf_fname, entry, section)
149         self.assertIn('has size 1: only 4 and 8 are supported',
150                       str(e.exception))
151
152     def testNoValue(self):
153         """Test the case where we have no value for the symbol
154
155         This should produce -1 values for all thress symbols, taking up the
156         first 16 bytes of the image.
157         """
158         entry = FakeEntry(24)
159         section = FakeSection(sym_value=None)
160         elf_fname = self.ElfTestFile('u_boot_binman_syms')
161         syms = elf.LookupAndWriteSymbols(elf_fname, entry, section)
162         self.assertEqual(tools.GetBytes(255, 20) + tools.GetBytes(ord('a'), 4),
163                                                                   entry.data)
164
165     def testDebug(self):
166         """Check that enabling debug in the elf module produced debug output"""
167         try:
168             tout.Init(tout.DEBUG)
169             entry = FakeEntry(20)
170             section = FakeSection()
171             elf_fname = self.ElfTestFile('u_boot_binman_syms')
172             with test_util.capture_sys_output() as (stdout, stderr):
173                 syms = elf.LookupAndWriteSymbols(elf_fname, entry, section)
174             self.assertTrue(len(stdout.getvalue()) > 0)
175         finally:
176             tout.Init(tout.WARNING)
177
178     def testMakeElf(self):
179         """Test for the MakeElf function"""
180         outdir = tempfile.mkdtemp(prefix='elf.')
181         expected_text = b'1234'
182         expected_data = b'wxyz'
183         elf_fname = os.path.join(outdir, 'elf')
184         bin_fname = os.path.join(outdir, 'bin')
185
186         # Make an Elf file and then convert it to a fkat binary file. This
187         # should produce the original data.
188         elf.MakeElf(elf_fname, expected_text, expected_data)
189         stdout = command.Output('objcopy', '-O', 'binary', elf_fname, bin_fname)
190         with open(bin_fname, 'rb') as fd:
191             data = fd.read()
192         self.assertEqual(expected_text + expected_data, data)
193         shutil.rmtree(outdir)
194
195     def testDecodeElf(self):
196         """Test for the MakeElf function"""
197         if not elf.ELF_TOOLS:
198             self.skipTest('Python elftools not available')
199         outdir = tempfile.mkdtemp(prefix='elf.')
200         expected_text = b'1234'
201         expected_data = b'wxyz'
202         elf_fname = os.path.join(outdir, 'elf')
203         elf.MakeElf(elf_fname, expected_text, expected_data)
204         data = tools.ReadFile(elf_fname)
205
206         load = 0xfef20000
207         entry = load + 2
208         expected = expected_text + expected_data
209         self.assertEqual(elf.ElfInfo(expected, load, entry, len(expected)),
210                          elf.DecodeElf(data, 0))
211         self.assertEqual(elf.ElfInfo(b'\0\0' + expected[2:],
212                                      load, entry, len(expected)),
213                          elf.DecodeElf(data, load + 2))
214         shutil.rmtree(outdir)
215
216
217 if __name__ == '__main__':
218     unittest.main()