diff --git a/tools/executable_analysis_tools/elf-float-checker.py b/tools/test/examples/elf_float_checker.py similarity index 77% rename from tools/executable_analysis_tools/elf-float-checker.py rename to tools/test/examples/elf_float_checker.py index c1185a7820..bc60e21806 100644 --- a/tools/executable_analysis_tools/elf-float-checker.py +++ b/tools/test/examples/elf_float_checker.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python # Copyright (c) 2019 Arm Limited and Contributors. All rights reserved. # # SPDX-License-Identifier: Apache-2.0 @@ -10,6 +10,15 @@ import logging import re import subprocess import sys +from enum import Enum + +class ReturnCode(Enum): + """Return codes.""" + + SUCCESS = 0 + ERROR = 1 + INVALID_OPTIONS = 2 + log = logging.getLogger(__name__) @@ -41,25 +50,26 @@ class SymbolParser: "Get the symbol table for ELF format file '{}'".format(elf_file) ) - cmd = [*OBJECT_FILE_ANALYSIS_CMD, elf_file] + cmd = [OBJECT_FILE_ANALYSIS_CMD[0], OBJECT_FILE_ANALYSIS_CMD[1], elf_file] log.debug("command: '{}'".format(cmd)) try: - process = subprocess.run( - cmd, - check=True, - stdin=None, - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - ) - except subprocess.CalledProcessError as error: - err_output = error.stdout.decode() - msg = ( + process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + except OSError as error: + raise SymbolTableError( "Getting symbol table for ELF format file '{}' failed," - " error: {}".format(elf_file, err_output) + " error: {}".format(elf_file, error) ) - raise SymbolTableError(msg) - symbol_table = process.stdout.decode() + stdout, _ = process.communicate() + + if process.returncode: + raise SymbolTableError( + "Getting symbol table for ELF format file '{}' failed," + " error: {}".format(elf_file, stdout.decode()) + ) + + symbol_table = stdout.decode() + log.debug("Symbol table:\n{}\n".format(symbol_table)) return symbol_table @@ -69,6 +79,9 @@ class SymbolTableError(Exception): """An exception for a failure to obtain a symbol table.""" +class FloatSymbolsFound(Exception): + """An exception generated when floating point symbols are found.""" + class ArgumentParserWithDefaultHelp(argparse.ArgumentParser): """Subclass that always shows the help message on invalid arguments.""" @@ -76,6 +89,7 @@ class ArgumentParserWithDefaultHelp(argparse.ArgumentParser): """Error handler.""" sys.stderr.write("error: {}\n".format(message)) self.print_help() + raise SystemExit(ReturnCode.INVALID_OPTIONS.value) def set_log_verbosity(increase_verbosity): @@ -91,6 +105,7 @@ def check_float_symbols(elf_file): Return the floating point symbols found. """ + print("Checking {} for floating point symbols".format(elf_file)) parser = SymbolParser() symbol_table = parser.get_symbol_table(elf_file) @@ -105,11 +120,12 @@ def check_action(args): """Entry point for checking the ELF file.""" float_symbols = check_float_symbols(args.elf_file) if float_symbols: - print("Found float symbols:") + print("Failed - Found float symbols:") for float_symbol in float_symbols: print(float_symbol) + raise FloatSymbolsFound("Found float symbols in {}".format(args.elf_file)) else: - print("No float symbols found.") + print("Passed - No float symbols found.") def parse_args(): @@ -160,9 +176,15 @@ def run_elf_floats_checker(): args.func(args) -if __name__ == "__main__": +def _main(): """Run elf-floats-checker.""" try: run_elf_floats_checker() except Exception as error: print(error) + return ReturnCode.ERROR.value + else: + return ReturnCode.SUCCESS.value + +if __name__ == "__main__": + sys.exit(_main()) diff --git a/tools/executable_analysis_tools/test_elf-float-checker.py b/tools/test/examples/test_elf_float_checker.py similarity index 50% rename from tools/executable_analysis_tools/test_elf-float-checker.py rename to tools/test/examples/test_elf_float_checker.py index 224dbb2296..2359da59fb 100644 --- a/tools/executable_analysis_tools/test_elf-float-checker.py +++ b/tools/test/examples/test_elf_float_checker.py @@ -7,11 +7,11 @@ import importlib import mock +import os import subprocess -from pathlib import Path -TARGET = importlib.import_module("elf-float-checker") +TARGET = importlib.import_module("elf_float_checker") SYMBOL_TABLE_WITHOUT_FLOATS = ( " Symbol table '.symtab' contains 2723 entries:\n" @@ -39,24 +39,28 @@ FLOAT_SYMBOLS = [ ] SYMBOL_TABLE_WITH_FLOATS = ( - " Symbol table '.symtab' contains 2723 entries:\n" - "Num: Value Size Type Bind Vis Ndx Name\n" - f" 0: 00000000 0 NOTYPE LOCAL DEFAULT UND \n" - f" 1: 000045fd 16 FUNC GLOBAL HIDDEN 3 {FLOAT_SYMBOLS[0]}\n" - f" 2: 00004609 16 FUNC GLOBAL HIDDEN 3 lp_ticker_disable_interrupt\n" - f" 3: 00004615 16 FUNC GLOBAL HIDDEN 3 {FLOAT_SYMBOLS[1]}\n" - f" 4: 00004625 36 FUNC GLOBAL HIDDEN 3 {FLOAT_SYMBOLS[2]}\n" - f" 5: 00004645 8 FUNC GLOBAL HIDDEN 3 lp_ticker_get_info\n" - f" 6: 0000464d 116 FUNC GLOBAL HIDDEN 3 {FLOAT_SYMBOLS[3]}\n" - f" 7: 000046bd 20 FUNC GLOBAL HIDDEN 3 lp_ticker_irq_handler\n" - f" 8: 000046d1 16 FUNC GLOBAL HIDDEN 3 {FLOAT_SYMBOLS[4]}\n" - f" 9: 000046e1 52 FUNC GLOBAL HIDDEN 3 {FLOAT_SYMBOLS[5]}\n" - f" 10: 000046f1 52 FUNC GLOBAL HIDDEN 3 {FLOAT_SYMBOLS[6]}\n" + " Symbol table '.symtab' contains 2723 entries:\n"+ + "Num: Value Size Type Bind Vis Ndx Name\n"+ + " 0: 00000000 0 NOTYPE LOCAL DEFAULT UND \n"+ + " 1: 000045fd 16 FUNC GLOBAL HIDDEN 3 {}\n".format(FLOAT_SYMBOLS[0])+ + " 2: 00004609 16 FUNC GLOBAL HIDDEN 3 lp_ticker_disable_interrupt\n"+ + " 3: 00004615 16 FUNC GLOBAL HIDDEN 3 {}\n".format(FLOAT_SYMBOLS[1])+ + " 4: 00004625 36 FUNC GLOBAL HIDDEN 3 {}\n".format(FLOAT_SYMBOLS[2])+ + " 5: 00004645 8 FUNC GLOBAL HIDDEN 3 lp_ticker_get_info\n"+ + " 6: 0000464d 116 FUNC GLOBAL HIDDEN 3 {}\n".format(FLOAT_SYMBOLS[3])+ + " 7: 000046bd 20 FUNC GLOBAL HIDDEN 3 lp_ticker_irq_handler\n"+ + " 8: 000046d1 16 FUNC GLOBAL HIDDEN 3 {}\n".format(FLOAT_SYMBOLS[4])+ + " 9: 000046e1 52 FUNC GLOBAL HIDDEN 3 {}\n".format(FLOAT_SYMBOLS[5])+ + " 10: 000046f1 52 FUNC GLOBAL HIDDEN 3 {}\n".format(FLOAT_SYMBOLS[6]) ) ELF_FORMAT_FILE = "mbed-os-example.elf" -OBJECT_FILE_ANALYSIS_CMD = [*(TARGET.OBJECT_FILE_ANALYSIS_CMD), f"{ELF_FORMAT_FILE}"] +OBJECT_FILE_ANALYSIS_CMD = [ + TARGET.OBJECT_FILE_ANALYSIS_CMD[0], + TARGET.OBJECT_FILE_ANALYSIS_CMD[1], + "{}".format(ELF_FORMAT_FILE) +] class TestElfFloatChecker: """Test class""" @@ -64,57 +68,55 @@ class TestElfFloatChecker: @classmethod def setup_class(cls): # Create a dummy ELF format file - Path(ELF_FORMAT_FILE).touch() + if not os.path.exists(ELF_FORMAT_FILE): + with open(ELF_FORMAT_FILE, 'w'): pass @classmethod def teardown_class(cls): # Remove the dummy ELF format file - Path(ELF_FORMAT_FILE).unlink() + if os.path.exists(ELF_FORMAT_FILE): + os.remove(ELF_FORMAT_FILE) - @mock.patch("subprocess.run") + @mock.patch("subprocess.Popen") def test_correctly_detect_absence_of_float_symbols( - self, mock_subprocess_run + self, mock_subprocess_popen ): """Test that no false positive occur.""" - mock_subprocess_run.return_value = subprocess.CompletedProcess( - args=( - f"{OBJECT_FILE_ANALYSIS_CMD}" - " check=True, stderr=-2, stdin=None, stdout=-1" + process_mock = mock.Mock() + attrs = { + "communicate.return_value":( + SYMBOL_TABLE_WITHOUT_FLOATS.encode(), None ), - returncode=0, - stdout=SYMBOL_TABLE_WITHOUT_FLOATS.encode(), - stderr=None, - ) + "returncode": 0, + } + process_mock.configure_mock(**attrs) + mock_subprocess_popen.return_value = process_mock assert [] == TARGET.check_float_symbols(ELF_FORMAT_FILE) - mock_subprocess_run.assert_called_with( + mock_subprocess_popen.assert_called_with( OBJECT_FILE_ANALYSIS_CMD, - check=True, - stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, ) - @mock.patch("subprocess.run") + @mock.patch("subprocess.Popen") def test_correctly_detect_presence_of_float_symbols( - self, mock_subprocess_run + self, mock_subprocess_popen ): """Test that float symbols can be discovered in a symbol table.""" - mock_subprocess_run.return_value = subprocess.CompletedProcess( - args=( - f"{OBJECT_FILE_ANALYSIS_CMD}" - " check=True, stderr=-2, stdin=None, stdout=-1" + process_mock = mock.Mock() + attrs = { + "communicate.return_value":( + SYMBOL_TABLE_WITH_FLOATS.encode(), None ), - returncode=0, - stdout=SYMBOL_TABLE_WITH_FLOATS.encode(), - stderr=None, - ) + "returncode": 0, + } + process_mock.configure_mock(**attrs) + mock_subprocess_popen.return_value = process_mock assert FLOAT_SYMBOLS == TARGET.check_float_symbols( ELF_FORMAT_FILE ) - mock_subprocess_run.assert_called_with( + mock_subprocess_popen.assert_called_with( OBJECT_FILE_ANALYSIS_CMD, - check=True, - stdin=None, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, )