blob: e2506377f262c0e2ce816ad70ab61ae073154c10 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001# SPDX-License-Identifier: GPL-2.0+
Simon Glassb50e5612017-11-13 18:54:54 -07002# Copyright (c) 2017 Google, Inc
3# Written by Simon Glass <sjg@chromium.org>
4#
Simon Glassb50e5612017-11-13 18:54:54 -07005# Test for the elf module
6
7import os
Simon Glassf58558a2019-07-08 13:18:34 -06008import shutil
Simon Glassb50e5612017-11-13 18:54:54 -07009import sys
Simon Glassf58558a2019-07-08 13:18:34 -060010import tempfile
Simon Glassb50e5612017-11-13 18:54:54 -070011import unittest
12
Simon Glassf58558a2019-07-08 13:18:34 -060013import command
Simon Glassb50e5612017-11-13 18:54:54 -070014import elf
Simon Glassc3f94542018-07-06 10:27:34 -060015import test_util
Simon Glasse0e62752018-10-01 21:12:41 -060016import tools
Simon Glassb50e5612017-11-13 18:54:54 -070017
18binman_dir = os.path.dirname(os.path.realpath(sys.argv[0]))
Simon Glass19790632017-11-13 18:55:01 -070019
Simon Glass19790632017-11-13 18:55:01 -070020
21class FakeEntry:
Simon Glassb2b0df82018-07-17 13:25:26 -060022 """A fake Entry object, usedfor testing
23
24 This supports an entry with a given size.
25 """
Simon Glass19790632017-11-13 18:55:01 -070026 def __init__(self, contents_size):
27 self.contents_size = contents_size
Simon Glassc6c10e72019-05-17 22:00:46 -060028 self.data = tools.GetBytes(ord('a'), contents_size)
Simon Glass19790632017-11-13 18:55:01 -070029
30 def GetPath(self):
31 return 'entry_path'
32
Simon Glassb2b0df82018-07-17 13:25:26 -060033
Simon Glassf55382b2018-06-01 09:38:13 -060034class FakeSection:
Simon Glassb2b0df82018-07-17 13:25:26 -060035 """A fake Section object, used for testing
36
37 This has the minimum feature set needed to support testing elf functions.
38 A LookupSymbol() function is provided which returns a fake value for amu
39 symbol requested.
40 """
Simon Glass19790632017-11-13 18:55:01 -070041 def __init__(self, sym_value=1):
42 self.sym_value = sym_value
43
44 def GetPath(self):
Simon Glassf55382b2018-06-01 09:38:13 -060045 return 'section_path'
Simon Glass19790632017-11-13 18:55:01 -070046
47 def LookupSymbol(self, name, weak, msg):
Simon Glassb2b0df82018-07-17 13:25:26 -060048 """Fake implementation which returns the same value for all symbols"""
Simon Glass19790632017-11-13 18:55:01 -070049 return self.sym_value
Simon Glassb50e5612017-11-13 18:54:54 -070050
Simon Glassb2b0df82018-07-17 13:25:26 -060051
Simon Glassb50e5612017-11-13 18:54:54 -070052class TestElf(unittest.TestCase):
Simon Glasse0e62752018-10-01 21:12:41 -060053 @classmethod
54 def setUpClass(self):
55 tools.SetInputDirs(['.'])
56
Simon Glassb50e5612017-11-13 18:54:54 -070057 def testAllSymbols(self):
Simon Glassb2b0df82018-07-17 13:25:26 -060058 """Test that we can obtain a symbol from the ELF file"""
Simon Glass19790632017-11-13 18:55:01 -070059 fname = os.path.join(binman_dir, 'test', 'u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -070060 syms = elf.GetSymbols(fname, [])
61 self.assertIn('.ucode', syms)
62
63 def testRegexSymbols(self):
Simon Glassb2b0df82018-07-17 13:25:26 -060064 """Test that we can obtain from the ELF file by regular expression"""
Simon Glass19790632017-11-13 18:55:01 -070065 fname = os.path.join(binman_dir, 'test', 'u_boot_ucode_ptr')
Simon Glassb50e5612017-11-13 18:54:54 -070066 syms = elf.GetSymbols(fname, ['ucode'])
67 self.assertIn('.ucode', syms)
68 syms = elf.GetSymbols(fname, ['missing'])
69 self.assertNotIn('.ucode', syms)
70 syms = elf.GetSymbols(fname, ['missing', 'ucode'])
71 self.assertIn('.ucode', syms)
72
Simon Glass19790632017-11-13 18:55:01 -070073 def testMissingFile(self):
Simon Glassb2b0df82018-07-17 13:25:26 -060074 """Test that a missing file is detected"""
Simon Glass19790632017-11-13 18:55:01 -070075 entry = FakeEntry(10)
Simon Glassf55382b2018-06-01 09:38:13 -060076 section = FakeSection()
Simon Glass19790632017-11-13 18:55:01 -070077 with self.assertRaises(ValueError) as e:
Simon Glassf55382b2018-06-01 09:38:13 -060078 syms = elf.LookupAndWriteSymbols('missing-file', entry, section)
Simon Glass19790632017-11-13 18:55:01 -070079 self.assertIn("Filename 'missing-file' not found in input path",
80 str(e.exception))
81
82 def testOutsideFile(self):
Simon Glassb2b0df82018-07-17 13:25:26 -060083 """Test a symbol which extends outside the entry area is detected"""
Simon Glass19790632017-11-13 18:55:01 -070084 entry = FakeEntry(10)
Simon Glassf55382b2018-06-01 09:38:13 -060085 section = FakeSection()
Simon Glass19790632017-11-13 18:55:01 -070086 elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms')
87 with self.assertRaises(ValueError) as e:
Simon Glassf55382b2018-06-01 09:38:13 -060088 syms = elf.LookupAndWriteSymbols(elf_fname, entry, section)
Simon Glass19790632017-11-13 18:55:01 -070089 self.assertIn('entry_path has offset 4 (size 8) but the contents size '
90 'is a', str(e.exception))
91
92 def testMissingImageStart(self):
Simon Glassb2b0df82018-07-17 13:25:26 -060093 """Test that we detect a missing __image_copy_start symbol
94
95 This is needed to mark the start of the image. Without it we cannot
96 locate the offset of a binman symbol within the image.
97 """
Simon Glass19790632017-11-13 18:55:01 -070098 entry = FakeEntry(10)
Simon Glassf55382b2018-06-01 09:38:13 -060099 section = FakeSection()
Simon Glass19790632017-11-13 18:55:01 -0700100 elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms_bad')
Simon Glassf55382b2018-06-01 09:38:13 -0600101 self.assertEqual(elf.LookupAndWriteSymbols(elf_fname, entry, section),
Simon Glass19790632017-11-13 18:55:01 -0700102 None)
103
104 def testBadSymbolSize(self):
Simon Glassb2b0df82018-07-17 13:25:26 -0600105 """Test that an attempt to use an 8-bit symbol are detected
106
107 Only 32 and 64 bits are supported, since we need to store an offset
108 into the image.
109 """
Simon Glass19790632017-11-13 18:55:01 -0700110 entry = FakeEntry(10)
Simon Glassf55382b2018-06-01 09:38:13 -0600111 section = FakeSection()
Simon Glass19790632017-11-13 18:55:01 -0700112 elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms_size')
113 with self.assertRaises(ValueError) as e:
Simon Glassf55382b2018-06-01 09:38:13 -0600114 syms = elf.LookupAndWriteSymbols(elf_fname, entry, section)
Simon Glass19790632017-11-13 18:55:01 -0700115 self.assertIn('has size 1: only 4 and 8 are supported',
116 str(e.exception))
117
118 def testNoValue(self):
Simon Glassb2b0df82018-07-17 13:25:26 -0600119 """Test the case where we have no value for the symbol
120
121 This should produce -1 values for all thress symbols, taking up the
122 first 16 bytes of the image.
123 """
Simon Glass19790632017-11-13 18:55:01 -0700124 entry = FakeEntry(20)
Simon Glassf55382b2018-06-01 09:38:13 -0600125 section = FakeSection(sym_value=None)
Simon Glass19790632017-11-13 18:55:01 -0700126 elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms')
Simon Glassf55382b2018-06-01 09:38:13 -0600127 syms = elf.LookupAndWriteSymbols(elf_fname, entry, section)
Simon Glassc6c10e72019-05-17 22:00:46 -0600128 self.assertEqual(tools.GetBytes(255, 16) + tools.GetBytes(ord('a'), 4),
129 entry.data)
Simon Glass19790632017-11-13 18:55:01 -0700130
131 def testDebug(self):
Simon Glassb2b0df82018-07-17 13:25:26 -0600132 """Check that enabling debug in the elf module produced debug output"""
Simon Glass19790632017-11-13 18:55:01 -0700133 elf.debug = True
134 entry = FakeEntry(20)
Simon Glassf55382b2018-06-01 09:38:13 -0600135 section = FakeSection()
Simon Glass19790632017-11-13 18:55:01 -0700136 elf_fname = os.path.join(binman_dir, 'test', 'u_boot_binman_syms')
Simon Glassc3f94542018-07-06 10:27:34 -0600137 with test_util.capture_sys_output() as (stdout, stderr):
Simon Glassf55382b2018-06-01 09:38:13 -0600138 syms = elf.LookupAndWriteSymbols(elf_fname, entry, section)
Simon Glass19790632017-11-13 18:55:01 -0700139 elf.debug = False
140 self.assertTrue(len(stdout.getvalue()) > 0)
141
Simon Glassf58558a2019-07-08 13:18:34 -0600142 def testMakeElf(self):
143 """Test for the MakeElf function"""
144 outdir = tempfile.mkdtemp(prefix='elf.')
145 expected_text = b'1234'
146 expected_data = b'wxyz'
147 elf_fname = os.path.join(outdir, 'elf')
148 bin_fname = os.path.join(outdir, 'elf')
149
150 # Make an Elf file and then convert it to a fkat binary file. This
151 # should produce the original data.
152 elf.MakeElf(elf_fname, expected_text, expected_data)
153 stdout = command.Output('objcopy', '-O', 'binary', elf_fname, bin_fname)
154 with open(bin_fname, 'rb') as fd:
155 data = fd.read()
156 self.assertEqual(expected_text + expected_data, data)
157 shutil.rmtree(outdir)
158
Simon Glassd8d40742019-07-08 13:18:35 -0600159 def testDecodeElf(self):
160 """Test for the MakeElf function"""
161 if not elf.ELF_TOOLS:
162 self.skipTest('Python elftools not available')
163 outdir = tempfile.mkdtemp(prefix='elf.')
164 expected_text = b'1234'
165 expected_data = b'wxyz'
166 elf_fname = os.path.join(outdir, 'elf')
167 elf.MakeElf(elf_fname, expected_text, expected_data)
168 data = tools.ReadFile(elf_fname)
169
170 load = 0xfef20000
171 entry = load + 2
172 expected = expected_text + expected_data
173 self.assertEqual(elf.ElfInfo(expected, load, entry, len(expected)),
174 elf.DecodeElf(data, 0))
175 self.assertEqual(elf.ElfInfo(b'\0\0' + expected[2:],
176 load, entry, len(expected)),
177 elf.DecodeElf(data, load + 2))
178 #shutil.rmtree(outdir)
179
Simon Glass19790632017-11-13 18:55:01 -0700180
Simon Glassb50e5612017-11-13 18:54:54 -0700181if __name__ == '__main__':
182 unittest.main()