mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			Merge pull request #11429 from hugueskamba/hk-no-float-validation
Move script to check for floats and make it Python 2 compatiblepull/11725/head
						commit
						5eeeaca670
					
				| 
						 | 
				
			
			@ -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())
 | 
			
		||||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
        )
 | 
			
		||||
		Loading…
	
		Reference in New Issue