Skip to content

Commit 1b31de8

Browse files
committed
Add executable analaysis tool for floating point checks.
1 parent b005bf2 commit 1b31de8

File tree

1 file changed

+168
-0
lines changed

1 file changed

+168
-0
lines changed
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2019 Arm Limited and Contributors. All rights reserved.
3+
#
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
"""Script for checking for floating point symbols in ELF files."""
7+
8+
import argparse
9+
import logging
10+
import re
11+
import subprocess
12+
import sys
13+
14+
log = logging.getLogger(__name__)
15+
16+
LOG_FORMAT = "%(asctime)s - %(levelname)s - %(message)s"
17+
FLOATING_POINT_SYMBOL_REGEX = r"__aeabi_(cd.+|cf.+|h2f.+|d.+|f.+|.+2d|.+2f)"
18+
19+
20+
class SymbolParser:
21+
"""Parse the given ELF format file."""
22+
23+
def get_symbols_from_table(self, symbol_table, symbol_regex):
24+
"""Get symbols matching a regular expression pattern from a table."""
25+
pattern = re.compile(symbol_regex, re.X)
26+
matched_symbols = []
27+
symbol_table_lines = symbol_table.split("\n")
28+
for symbol_table_line in symbol_table_lines:
29+
match = pattern.search(symbol_table_line)
30+
if match:
31+
log.debug("Symbol line: {}".format(symbol_table_line))
32+
log.debug("Match found: {}".format(match))
33+
matched_symbols.append(match.group(0))
34+
35+
log.debug("Symbols found:\n'{}'".format(matched_symbols))
36+
return matched_symbols
37+
38+
def get_symbol_table(self, elf_file):
39+
"""Get the symbol table from an ELF format file."""
40+
log.debug(
41+
"Get the symbol table for ELF format file '{}'".format(elf_file)
42+
)
43+
# Command syntax:
44+
# `arm-none-eabi-readelf --symbols <elf_file>`
45+
cmd = ["arm-none-eabi-readelf", "--symbols", elf_file]
46+
try:
47+
process = subprocess.run(
48+
cmd,
49+
check=True,
50+
stdin=None,
51+
stdout=subprocess.PIPE,
52+
stderr=subprocess.STDOUT,
53+
)
54+
except subprocess.CalledProcessError as error:
55+
err_output = error.stdout.decode()
56+
msg = (
57+
"Getting symbol table for ELF format file '{}' failed,"
58+
" error: {}".format(elf_file, err_output)
59+
)
60+
raise SymbolTableError(msg)
61+
62+
symbol_table = process.stdout.decode()
63+
log.debug("Symbol table:\n{}\n".format(symbol_table))
64+
65+
return symbol_table
66+
67+
68+
class SymbolTableError(Exception):
69+
"""An exception for a failure to obtain a symbol table."""
70+
71+
72+
class ArgumentParserWithDefaultHelp(argparse.ArgumentParser):
73+
"""Subclass that always shows the help message on invalid arguments."""
74+
75+
def error(self, message):
76+
"""Error handler."""
77+
sys.stderr.write("error: {}\n".format(message))
78+
self.print_help()
79+
80+
81+
def set_log_verbosity(increase_verbosity):
82+
"""Set the verbosity of the log output."""
83+
log_level = logging.DEBUG if increase_verbosity else logging.INFO
84+
85+
log.setLevel(log_level)
86+
logging.basicConfig(level=log_level, format=LOG_FORMAT)
87+
88+
89+
def check_float_symbols(elf_file):
90+
"""Check for floating point symbols in ELF format file.
91+
92+
Return the floating point symbols found.
93+
"""
94+
parser = SymbolParser()
95+
symbol_table = parser.get_symbol_table(elf_file)
96+
97+
float_symbols = parser.get_symbols_from_table(
98+
symbol_table, FLOATING_POINT_SYMBOL_REGEX
99+
)
100+
101+
return float_symbols
102+
103+
104+
def check_action(args):
105+
"""Entry point for checking the ELF file."""
106+
float_symbols = check_float_symbols(args.elf_file)
107+
if float_symbols:
108+
print("Found float symbols:")
109+
for float_symbol in float_symbols:
110+
print(float_symbol)
111+
else:
112+
print("No float symbols found.")
113+
114+
115+
def parse_args():
116+
"""Parse the command line args."""
117+
parser = ArgumentParserWithDefaultHelp(
118+
description="ELF floats checker",
119+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
120+
)
121+
122+
parser.add_argument(
123+
"elf_file",
124+
type=str,
125+
help=(
126+
"the Executable and Linkable Format (ELF) file to check"
127+
" for floating point instruction inclusion."
128+
),
129+
)
130+
131+
parser.add_argument(
132+
"-v",
133+
"--verbose",
134+
action="store_true",
135+
help="increase verbosity of status information.",
136+
)
137+
138+
parser.set_defaults(func=check_action)
139+
140+
args_namespace = parser.parse_args()
141+
142+
# We want to fail gracefully, with a consistent
143+
# help message, in the no argument case.
144+
# So here's an obligatory hasattr hack.
145+
if not hasattr(args_namespace, "func"):
146+
parser.error("No arguments given!")
147+
else:
148+
return args_namespace
149+
150+
151+
def run_elf_floats_checker():
152+
"""Application main algorithm."""
153+
args = parse_args()
154+
155+
set_log_verbosity(args.verbose)
156+
157+
log.debug("Starting elf-floats-checker")
158+
log.debug("Command line arguments:{}".format(args))
159+
160+
args.func(args)
161+
162+
163+
if __name__ == "__main__":
164+
"""Run elf-floats-checker."""
165+
try:
166+
run_elf_floats_checker()
167+
except Exception as error:
168+
print(error)

0 commit comments

Comments
 (0)