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.
#
# 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())

View File

@ -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,
)