1 # SPDX-License-Identifier: GPL-2.0+
2 # Copyright (c) 2017 Google, Inc
3 # Written by Simon Glass <sjg@chromium.org>
5 # Test for the elf module
19 binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
23 """A fake Entry object, usedfor testing
25 This supports an entry with a given size.
27 def __init__(self, contents_size):
28 self.contents_size = contents_size
29 self.data = tools.GetBytes(ord('a'), contents_size)
36 """A fake Section object, used for testing
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
42 def __init__(self, sym_value=1):
43 self.sym_value = sym_value
48 def LookupSymbol(self, name, weak, msg):
49 """Fake implementation which returns the same value for all symbols"""
53 def BuildElfTestFiles(target_dir):
54 """Build ELF files used for testing in binman
56 This compiles and links the test files into the specified directory. It the
57 Makefile and source files in the binman test/ directory.
60 target_dir: Directory to put the files into
62 if not os.path.exists(target_dir):
64 testdir = os.path.join(binman_dir, 'test')
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 'bss_data', 'u_boot_ucode_ptr', 'u_boot_no_ucode_ptr',
74 'u_boot_binman_syms', 'u_boot_binman_syms.bin')
77 class TestElf(unittest.TestCase):
80 cls._indir = tempfile.mkdtemp(prefix='elf.')
81 tools.SetInputDirs(['.'])
82 BuildElfTestFiles(cls._indir)
85 def tearDownClass(cls):
87 shutil.rmtree(cls._indir)
90 def ElfTestFile(cls, fname):
91 return os.path.join(cls._indir, fname)
93 def testAllSymbols(self):
94 """Test that we can obtain a symbol from the ELF file"""
95 fname = self.ElfTestFile('u_boot_ucode_ptr')
96 syms = elf.GetSymbols(fname, [])
97 self.assertIn('.ucode', syms)
99 def testRegexSymbols(self):
100 """Test that we can obtain from the ELF file by regular expression"""
101 fname = self.ElfTestFile('u_boot_ucode_ptr')
102 syms = elf.GetSymbols(fname, ['ucode'])
103 self.assertIn('.ucode', syms)
104 syms = elf.GetSymbols(fname, ['missing'])
105 self.assertNotIn('.ucode', syms)
106 syms = elf.GetSymbols(fname, ['missing', 'ucode'])
107 self.assertIn('.ucode', syms)
109 def testMissingFile(self):
110 """Test that a missing file is detected"""
111 entry = FakeEntry(10)
112 section = FakeSection()
113 with self.assertRaises(ValueError) as e:
114 syms = elf.LookupAndWriteSymbols('missing-file', entry, section)
115 self.assertIn("Filename 'missing-file' not found in input path",
118 def testOutsideFile(self):
119 """Test a symbol which extends outside the entry area is detected"""
120 entry = FakeEntry(10)
121 section = FakeSection()
122 elf_fname = self.ElfTestFile('u_boot_binman_syms')
123 with self.assertRaises(ValueError) as e:
124 syms = elf.LookupAndWriteSymbols(elf_fname, entry, section)
125 self.assertIn('entry_path has offset 4 (size 8) but the contents size '
126 'is a', str(e.exception))
128 def testMissingImageStart(self):
129 """Test that we detect a missing __image_copy_start symbol
131 This is needed to mark the start of the image. Without it we cannot
132 locate the offset of a binman symbol within the image.
134 entry = FakeEntry(10)
135 section = FakeSection()
136 elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms_bad')
137 self.assertEqual(elf.LookupAndWriteSymbols(elf_fname, entry, section),
140 def testBadSymbolSize(self):
141 """Test that an attempt to use an 8-bit symbol are detected
143 Only 32 and 64 bits are supported, since we need to store an offset
146 entry = FakeEntry(10)
147 section = FakeSection()
148 elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms_size')
149 with self.assertRaises(ValueError) as e:
150 syms = elf.LookupAndWriteSymbols(elf_fname, entry, section)
151 self.assertIn('has size 1: only 4 and 8 are supported',
154 def testNoValue(self):
155 """Test the case where we have no value for the symbol
157 This should produce -1 values for all thress symbols, taking up the
158 first 16 bytes of the image.
160 entry = FakeEntry(20)
161 section = FakeSection(sym_value=None)
162 elf_fname = self.ElfTestFile('u_boot_binman_syms')
163 syms = elf.LookupAndWriteSymbols(elf_fname, entry, section)
164 self.assertEqual(tools.GetBytes(255, 16) + tools.GetBytes(ord('a'), 4),
168 """Check that enabling debug in the elf module produced debug output"""
170 tout.Init(tout.DEBUG)
171 entry = FakeEntry(20)
172 section = FakeSection()
173 elf_fname = self.ElfTestFile('u_boot_binman_syms')
174 with test_util.capture_sys_output() as (stdout, stderr):
175 syms = elf.LookupAndWriteSymbols(elf_fname, entry, section)
176 self.assertTrue(len(stdout.getvalue()) > 0)
178 tout.Init(tout.WARNING)
180 def testMakeElf(self):
181 """Test for the MakeElf function"""
182 outdir = tempfile.mkdtemp(prefix='elf.')
183 expected_text = b'1234'
184 expected_data = b'wxyz'
185 elf_fname = os.path.join(outdir, 'elf')
186 bin_fname = os.path.join(outdir, 'bin')
188 # Make an Elf file and then convert it to a fkat binary file. This
189 # should produce the original data.
190 elf.MakeElf(elf_fname, expected_text, expected_data)
191 stdout = command.Output('objcopy', '-O', 'binary', elf_fname, bin_fname)
192 with open(bin_fname, 'rb') as fd:
194 self.assertEqual(expected_text + expected_data, data)
195 shutil.rmtree(outdir)
197 def testDecodeElf(self):
198 """Test for the MakeElf function"""
199 if not elf.ELF_TOOLS:
200 self.skipTest('Python elftools not available')
201 outdir = tempfile.mkdtemp(prefix='elf.')
202 expected_text = b'1234'
203 expected_data = b'wxyz'
204 elf_fname = os.path.join(outdir, 'elf')
205 elf.MakeElf(elf_fname, expected_text, expected_data)
206 data = tools.ReadFile(elf_fname)
210 expected = expected_text + expected_data
211 self.assertEqual(elf.ElfInfo(expected, load, entry, len(expected)),
212 elf.DecodeElf(data, 0))
213 self.assertEqual(elf.ElfInfo(b'\0\0' + expected[2:],
214 load, entry, len(expected)),
215 elf.DecodeElf(data, load + 2))
216 shutil.rmtree(outdir)
219 if __name__ == '__main__':