diff --git a/tools/binman/binman.py b/tools/binman/binman.py index 3ccf25f1f8..81a613ddc4 100755 --- a/tools/binman/binman.py +++ b/tools/binman/binman.py @@ -33,6 +33,7 @@ import control def RunTests(): """Run the functional tests and any embedded doctests""" + import elf_test import entry_test import fdt_test import ftest @@ -50,7 +51,7 @@ def RunTests(): # 'entry' module. suite = unittest.TestLoader().loadTestsFromTestCase(entry_test.TestEntry) suite.run(result) - for module in (ftest.TestFunctional, fdt_test.TestFdt): + for module in (ftest.TestFunctional, fdt_test.TestFdt, elf_test.TestElf): suite = unittest.TestLoader().loadTestsFromTestCase(module) suite.run(result) diff --git a/tools/binman/elf.py b/tools/binman/elf.py new file mode 100644 index 0000000000..97208b1795 --- /dev/null +++ b/tools/binman/elf.py @@ -0,0 +1,77 @@ +# Copyright (c) 2016 Google, Inc +# Written by Simon Glass +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Handle various things related to ELF images +# + +from collections import namedtuple, OrderedDict +import command +import os +import re +import struct + +import tools + +Symbol = namedtuple('Symbol', ['section', 'address', 'size', 'weak']) + +# Used for tests which don't have an ELF file to read +ignore_missing_files = False + + +def GetSymbols(fname, patterns): + """Get the symbols from an ELF file + + Args: + fname: Filename of the ELF file to read + patterns: List of regex patterns to search for, each a string + + Returns: + None, if the file does not exist, or Dict: + key: Name of symbol + value: Hex value of symbol + """ + stdout = command.Output('objdump', '-t', fname, raise_on_error=False) + lines = stdout.splitlines() + if patterns: + re_syms = re.compile('|'.join(patterns)) + else: + re_syms = None + syms = {} + syms_started = False + for line in lines: + if not line or not syms_started: + if 'SYMBOL TABLE' in line: + syms_started = True + line = None # Otherwise code coverage complains about 'continue' + continue + if re_syms and not re_syms.search(line): + continue + + space_pos = line.find(' ') + value, rest = line[:space_pos], line[space_pos + 1:] + flags = rest[:7] + parts = rest[7:].split() + section, size = parts[:2] + if len(parts) > 2: + name = parts[2] + syms[name] = Symbol(section, int(value, 16), int(size,16), + flags[1] == 'w') + return syms + +def GetSymbolAddress(fname, sym_name): + """Get a value of a symbol from an ELF file + + Args: + fname: Filename of the ELF file to read + patterns: List of regex patterns to search for, each a string + + Returns: + Symbol value (as an integer) or None if not found + """ + syms = GetSymbols(fname, [sym_name]) + sym = syms.get(sym_name) + if not sym: + return None + return sym.address diff --git a/tools/binman/elf_test.py b/tools/binman/elf_test.py new file mode 100644 index 0000000000..dca7bc59f9 --- /dev/null +++ b/tools/binman/elf_test.py @@ -0,0 +1,32 @@ +# +# Copyright (c) 2017 Google, Inc +# Written by Simon Glass +# +# SPDX-License-Identifier: GPL-2.0+ +# +# Test for the elf module + +import os +import sys +import unittest + +import elf + +binman_dir = os.path.dirname(os.path.realpath(sys.argv[0])) +fname = os.path.join(binman_dir, 'test', 'u_boot_ucode_ptr') + +class TestElf(unittest.TestCase): + def testAllSymbols(self): + syms = elf.GetSymbols(fname, []) + self.assertIn('.ucode', syms) + + def testRegexSymbols(self): + syms = elf.GetSymbols(fname, ['ucode']) + self.assertIn('.ucode', syms) + syms = elf.GetSymbols(fname, ['missing']) + self.assertNotIn('.ucode', syms) + syms = elf.GetSymbols(fname, ['missing', 'ucode']) + self.assertIn('.ucode', syms) + +if __name__ == '__main__': + unittest.main() diff --git a/tools/binman/etype/u_boot_spl_bss_pad.py b/tools/binman/etype/u_boot_spl_bss_pad.py index c005f28191..c37f61db23 100644 --- a/tools/binman/etype/u_boot_spl_bss_pad.py +++ b/tools/binman/etype/u_boot_spl_bss_pad.py @@ -9,6 +9,7 @@ # import command +import elf from entry import Entry from blob import Entry_blob import tools @@ -19,8 +20,8 @@ class Entry_u_boot_spl_bss_pad(Entry_blob): def ObtainContents(self): fname = tools.GetInputFilename('spl/u-boot-spl') - args = [['nm', fname], ['grep', '__bss_size']] - out = command.RunPipe(args, capture=True).stdout.splitlines() - bss_size = int(out[0].split()[0], 16) + bss_size = elf.GetSymbolAddress(fname, '__bss_size') + if not bss_size: + self.Raise('Expected __bss_size symbol in spl/u-boot-spl') self.data = chr(0) * bss_size self.contents_size = bss_size diff --git a/tools/binman/etype/u_boot_with_ucode_ptr.py b/tools/binman/etype/u_boot_with_ucode_ptr.py index 6f01adb970..99b437130d 100644 --- a/tools/binman/etype/u_boot_with_ucode_ptr.py +++ b/tools/binman/etype/u_boot_with_ucode_ptr.py @@ -9,6 +9,7 @@ import struct import command +import elf from entry import Entry from blob import Entry_blob import fdt_util @@ -31,11 +32,9 @@ class Entry_u_boot_with_ucode_ptr(Entry_blob): def ObtainContents(self): # Figure out where to put the microcode pointer fname = tools.GetInputFilename(self.elf_fname) - args = [['nm', fname], ['grep', '-w', '_dt_ucode_base_size']] - out = (command.RunPipe(args, capture=True, raise_on_error=False). - stdout.splitlines()) - if len(out) == 1: - self.target_pos = int(out[0].split()[0], 16) + sym = elf.GetSymbolAddress(fname, '_dt_ucode_base_size') + if sym: + self.target_pos = sym elif not fdt_util.GetBool(self._node, 'optional-ucode'): self.Raise('Cannot locate _dt_ucode_base_size symbol in u-boot') diff --git a/tools/binman/ftest.py b/tools/binman/ftest.py index 9083143894..c8155788af 100644 --- a/tools/binman/ftest.py +++ b/tools/binman/ftest.py @@ -835,6 +835,13 @@ class TestFunctional(unittest.TestCase): data = self._DoReadFile('47_spl_bss_pad.dts') self.assertEqual(U_BOOT_SPL_DATA + (chr(0) * 10) + U_BOOT_DATA, data) + with open(self.TestFile('u_boot_ucode_ptr')) as fd: + TestFunctional._MakeInputFile('spl/u-boot-spl', fd.read()) + with self.assertRaises(ValueError) as e: + data = self._DoReadFile('47_spl_bss_pad.dts') + self.assertIn('Expected __bss_size symbol in spl/u-boot-spl', + str(e.exception)) + def testPackStart16Spl(self): """Test that an image with an x86 start16 region can be created""" data = self._DoReadFile('48_x86-start16-spl.dts') diff --git a/tools/binman/test/bss_data.c b/tools/binman/test/bss_data.c index f865a9d9f6..e0305c382c 100644 --- a/tools/binman/test/bss_data.c +++ b/tools/binman/test/bss_data.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-2.0+ * * Simple program to create a _dt_ucode_base_size symbol which can be read - * by 'nm'. This is used by binman tests. + * by binutils. This is used by binman tests. */ int bss_data[10]; diff --git a/tools/binman/test/u_boot_ucode_ptr.c b/tools/binman/test/u_boot_ucode_ptr.c index 24f349fb9e..734d54f0d4 100644 --- a/tools/binman/test/u_boot_ucode_ptr.c +++ b/tools/binman/test/u_boot_ucode_ptr.c @@ -4,7 +4,7 @@ * SPDX-License-Identifier: GPL-2.0+ * * Simple program to create a _dt_ucode_base_size symbol which can be read - * by 'nm'. This is used by binman tests. + * by binutils. This is used by binman tests. */ static unsigned long _dt_ucode_base_size[2]