Move script to check for floats and make it Python 2 compatible.

All scripts pertaining to example projects tests should be in the same
directory. The test framework uses Python2 therefore this script also needs
to be Python2 compatible.
pull/11429/head
Hugues Kamba 2019-09-05 08:13:49 +01:00
parent 1798c246cc
commit c712d2f6ee
2 changed files with 86 additions and 62 deletions

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python3 #!/usr/bin/env python
# Copyright (c) 2019 Arm Limited and Contributors. All rights reserved. # Copyright (c) 2019 Arm Limited and Contributors. All rights reserved.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
@ -10,6 +10,15 @@ import logging
import re import re
import subprocess import subprocess
import sys import sys
from enum import Enum
class ReturnCode(Enum):
"""Return codes."""
SUCCESS = 0
ERROR = 1
INVALID_OPTIONS = 2
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -41,25 +50,26 @@ class SymbolParser:
"Get the symbol table for ELF format file '{}'".format(elf_file) "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)) log.debug("command: '{}'".format(cmd))
try: try:
process = subprocess.run( process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
cmd, except OSError as error:
check=True, raise SymbolTableError(
stdin=None,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
except subprocess.CalledProcessError as error:
err_output = error.stdout.decode()
msg = (
"Getting symbol table for ELF format file '{}' failed," "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)) log.debug("Symbol table:\n{}\n".format(symbol_table))
return symbol_table return symbol_table
@ -69,6 +79,9 @@ class SymbolTableError(Exception):
"""An exception for a failure to obtain a symbol table.""" """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): class ArgumentParserWithDefaultHelp(argparse.ArgumentParser):
"""Subclass that always shows the help message on invalid arguments.""" """Subclass that always shows the help message on invalid arguments."""
@ -76,6 +89,7 @@ class ArgumentParserWithDefaultHelp(argparse.ArgumentParser):
"""Error handler.""" """Error handler."""
sys.stderr.write("error: {}\n".format(message)) sys.stderr.write("error: {}\n".format(message))
self.print_help() self.print_help()
raise SystemExit(ReturnCode.INVALID_OPTIONS.value)
def set_log_verbosity(increase_verbosity): def set_log_verbosity(increase_verbosity):
@ -91,6 +105,7 @@ def check_float_symbols(elf_file):
Return the floating point symbols found. Return the floating point symbols found.
""" """
print("Checking {} for floating point symbols".format(elf_file))
parser = SymbolParser() parser = SymbolParser()
symbol_table = parser.get_symbol_table(elf_file) symbol_table = parser.get_symbol_table(elf_file)
@ -105,11 +120,12 @@ def check_action(args):
"""Entry point for checking the ELF file.""" """Entry point for checking the ELF file."""
float_symbols = check_float_symbols(args.elf_file) float_symbols = check_float_symbols(args.elf_file)
if float_symbols: if float_symbols:
print("Found float symbols:") print("Failed - Found float symbols:")
for float_symbol in float_symbols: for float_symbol in float_symbols:
print(float_symbol) print(float_symbol)
raise FloatSymbolsFound("Found float symbols in {}".format(args.elf_file))
else: else:
print("No float symbols found.") print("Passed - No float symbols found.")
def parse_args(): def parse_args():
@ -160,9 +176,15 @@ def run_elf_floats_checker():
args.func(args) args.func(args)
if __name__ == "__main__": def _main():
"""Run elf-floats-checker.""" """Run elf-floats-checker."""
try: try:
run_elf_floats_checker() run_elf_floats_checker()
except Exception as error: except Exception as error:
print(error) print(error)
return ReturnCode.ERROR.value
else:
return ReturnCode.SUCCESS.value
if __name__ == "__main__":
sys.exit(_main())

View File

@ -7,11 +7,11 @@
import importlib import importlib
import mock import mock
import os
import subprocess 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_WITHOUT_FLOATS = (
" Symbol table '.symtab' contains 2723 entries:\n" " Symbol table '.symtab' contains 2723 entries:\n"
@ -39,24 +39,28 @@ FLOAT_SYMBOLS = [
] ]
SYMBOL_TABLE_WITH_FLOATS = ( SYMBOL_TABLE_WITH_FLOATS = (
" Symbol table '.symtab' contains 2723 entries:\n" " Symbol table '.symtab' contains 2723 entries:\n"+
"Num: Value Size Type Bind Vis Ndx Name\n" "Num: Value Size Type Bind Vis Ndx Name\n"+
f" 0: 00000000 0 NOTYPE LOCAL DEFAULT UND \n" " 0: 00000000 0 NOTYPE LOCAL DEFAULT UND \n"+
f" 1: 000045fd 16 FUNC GLOBAL HIDDEN 3 {FLOAT_SYMBOLS[0]}\n" " 1: 000045fd 16 FUNC GLOBAL HIDDEN 3 {}\n".format(FLOAT_SYMBOLS[0])+
f" 2: 00004609 16 FUNC GLOBAL HIDDEN 3 lp_ticker_disable_interrupt\n" " 2: 00004609 16 FUNC GLOBAL HIDDEN 3 lp_ticker_disable_interrupt\n"+
f" 3: 00004615 16 FUNC GLOBAL HIDDEN 3 {FLOAT_SYMBOLS[1]}\n" " 3: 00004615 16 FUNC GLOBAL HIDDEN 3 {}\n".format(FLOAT_SYMBOLS[1])+
f" 4: 00004625 36 FUNC GLOBAL HIDDEN 3 {FLOAT_SYMBOLS[2]}\n" " 4: 00004625 36 FUNC GLOBAL HIDDEN 3 {}\n".format(FLOAT_SYMBOLS[2])+
f" 5: 00004645 8 FUNC GLOBAL HIDDEN 3 lp_ticker_get_info\n" " 5: 00004645 8 FUNC GLOBAL HIDDEN 3 lp_ticker_get_info\n"+
f" 6: 0000464d 116 FUNC GLOBAL HIDDEN 3 {FLOAT_SYMBOLS[3]}\n" " 6: 0000464d 116 FUNC GLOBAL HIDDEN 3 {}\n".format(FLOAT_SYMBOLS[3])+
f" 7: 000046bd 20 FUNC GLOBAL HIDDEN 3 lp_ticker_irq_handler\n" " 7: 000046bd 20 FUNC GLOBAL HIDDEN 3 lp_ticker_irq_handler\n"+
f" 8: 000046d1 16 FUNC GLOBAL HIDDEN 3 {FLOAT_SYMBOLS[4]}\n" " 8: 000046d1 16 FUNC GLOBAL HIDDEN 3 {}\n".format(FLOAT_SYMBOLS[4])+
f" 9: 000046e1 52 FUNC GLOBAL HIDDEN 3 {FLOAT_SYMBOLS[5]}\n" " 9: 000046e1 52 FUNC GLOBAL HIDDEN 3 {}\n".format(FLOAT_SYMBOLS[5])+
f" 10: 000046f1 52 FUNC GLOBAL HIDDEN 3 {FLOAT_SYMBOLS[6]}\n" " 10: 000046f1 52 FUNC GLOBAL HIDDEN 3 {}\n".format(FLOAT_SYMBOLS[6])
) )
ELF_FORMAT_FILE = "mbed-os-example.elf" 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: class TestElfFloatChecker:
"""Test class""" """Test class"""
@ -64,57 +68,55 @@ class TestElfFloatChecker:
@classmethod @classmethod
def setup_class(cls): def setup_class(cls):
# Create a dummy ELF format file # 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 @classmethod
def teardown_class(cls): def teardown_class(cls):
# Remove the dummy ELF format file # 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( def test_correctly_detect_absence_of_float_symbols(
self, mock_subprocess_run self, mock_subprocess_popen
): ):
"""Test that no false positive occur.""" """Test that no false positive occur."""
mock_subprocess_run.return_value = subprocess.CompletedProcess( process_mock = mock.Mock()
args=( attrs = {
f"{OBJECT_FILE_ANALYSIS_CMD}" "communicate.return_value":(
" check=True, stderr=-2, stdin=None, stdout=-1" SYMBOL_TABLE_WITHOUT_FLOATS.encode(), None
), ),
returncode=0, "returncode": 0,
stdout=SYMBOL_TABLE_WITHOUT_FLOATS.encode(), }
stderr=None, process_mock.configure_mock(**attrs)
) mock_subprocess_popen.return_value = process_mock
assert [] == TARGET.check_float_symbols(ELF_FORMAT_FILE) assert [] == TARGET.check_float_symbols(ELF_FORMAT_FILE)
mock_subprocess_run.assert_called_with( mock_subprocess_popen.assert_called_with(
OBJECT_FILE_ANALYSIS_CMD, OBJECT_FILE_ANALYSIS_CMD,
check=True,
stdin=None,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, stderr=subprocess.STDOUT,
) )
@mock.patch("subprocess.run") @mock.patch("subprocess.Popen")
def test_correctly_detect_presence_of_float_symbols( 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.""" """Test that float symbols can be discovered in a symbol table."""
mock_subprocess_run.return_value = subprocess.CompletedProcess( process_mock = mock.Mock()
args=( attrs = {
f"{OBJECT_FILE_ANALYSIS_CMD}" "communicate.return_value":(
" check=True, stderr=-2, stdin=None, stdout=-1" SYMBOL_TABLE_WITH_FLOATS.encode(), None
), ),
returncode=0, "returncode": 0,
stdout=SYMBOL_TABLE_WITH_FLOATS.encode(), }
stderr=None, process_mock.configure_mock(**attrs)
) mock_subprocess_popen.return_value = process_mock
assert FLOAT_SYMBOLS == TARGET.check_float_symbols( assert FLOAT_SYMBOLS == TARGET.check_float_symbols(
ELF_FORMAT_FILE ELF_FORMAT_FILE
) )
mock_subprocess_run.assert_called_with( mock_subprocess_popen.assert_called_with(
OBJECT_FILE_ANALYSIS_CMD, OBJECT_FILE_ANALYSIS_CMD,
check=True,
stdin=None,
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, stderr=subprocess.STDOUT,
) )