blob: a949e72a6f202b6f25f890b088810078a2190616 [file] [log] [blame]
David Brazdil6c63a262019-12-23 13:23:46 +00001#!/usr/bin/env python3
David Brazdild623d312019-12-19 16:04:06 +00002#
3# Copyright 2019 The Hafnium Authors.
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# https://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16
David Brazdild623d312019-12-19 16:04:06 +000017"""Check ELF file for assembly-level regressions.
18
19Objdumps the given ELF file and detects known assembly patterns, checking for
20regressions on bugs such as CPU erratas. Throws an exception if a broken pattern
21is detected.
22"""
23
24import argparse
25import os
26import re
27import subprocess
28import sys
29
30HF_ROOT = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
31CLANG_ROOT = os.path.join(HF_ROOT, "prebuilts", "linux-x64", "clang")
32OBJDUMP = os.path.join(CLANG_ROOT, "bin", "llvm-objdump")
David Brazdila2f45212020-01-20 13:19:31 +000033NM = os.path.join(CLANG_ROOT, "bin", "llvm-nm")
David Brazdild623d312019-12-19 16:04:06 +000034
David Brazdila2f45212020-01-20 13:19:31 +000035def check_eret_speculation_barrier(args):
David Brazdild623d312019-12-19 16:04:06 +000036 """
37 Some ARM64 CPUs speculatively execute instructions after ERET.
38 Check that every ERET is followed by DSB NSH and ISB.
39 """
David Brazdila2f45212020-01-20 13:19:31 +000040
41 objdump_stdout = subprocess\
42 .check_output([ OBJDUMP, "-d", args.input_elf ])\
43 .decode("utf-8")\
44 .splitlines()
45
David Brazdild623d312019-12-19 16:04:06 +000046 found_eret = False
47
48 STATE_DEFAULT = 1
49 STATE_EXPECT_DSB_NSH = 2
50 STATE_EXPECT_ISB = 3
51
52 REGEX_ERET = re.compile(r"^\s*[0-9a-f]+:\s*e0 03 9f d6\s+eret$")
53 REGEX_DSB_NSH = re.compile(r"^\s*[0-9a-f]+:\s*9f 37 03 d5\s*dsb\s+nsh$")
54 REGEX_ISB = re.compile(r"^\s*[0-9a-f]+:\s*df 3f 03 d5\s+isb$")
55
56 state = STATE_DEFAULT
57 for line in objdump_stdout:
58 if state == STATE_DEFAULT:
59 if re.match(REGEX_ERET, line):
60 found_eret = True
61 state = STATE_EXPECT_DSB_NSH
62 elif state == STATE_EXPECT_DSB_NSH:
63 if re.match(REGEX_DSB_NSH, line):
64 state = STATE_EXPECT_ISB
65 else:
66 raise Exception("ERET not followed by DSB NSH")
67 elif state == STATE_EXPECT_ISB:
68 if re.match(REGEX_ISB, line):
69 state = STATE_DEFAULT
70 else:
71 raise Exception("ERET not followed by ISB")
72
73 # Ensure that at least one instance was found, otherwise the regexes are
74 # probably wrong.
75 if not found_eret:
76 raise Exception("Could not find any ERET instructions")
77
David Brazdila2f45212020-01-20 13:19:31 +000078def check_max_image_size(args):
79 """
80 Check that the ELF's effective image size does not exceed maximum
81 allowed image size, if specified in command-line arguments.
82 """
83
84 if args.max_image_size <= 0:
85 return
86
87 nm_stdout = subprocess\
88 .check_output([ NM, args.input_elf ])\
89 .decode("utf-8")\
90 .splitlines()
91
92 COLUMN_COUNT = 3
93 COLUMN_IDX_VALUE = 0
94 COLUMN_IDX_TYPE = 1
95 COLUMN_IDX_NAME = 2
96
97 image_size = None
98 for line in nm_stdout:
99 line = line.split()
100 if len(line) != COLUMN_COUNT:
101 raise Exception(
102 "Unexpected number of columns in NM output")
103
104 if line[COLUMN_IDX_NAME] == "image_size":
105 if line[COLUMN_IDX_TYPE] != "A":
106 raise Exception(
107 "Unexpected type of image_size symbol")
108 image_size = int(line[COLUMN_IDX_VALUE], 16)
109 break
110
111 if image_size is None:
112 raise Exception("Could not find value of image_size symbol")
113 elif image_size > args.max_image_size:
114 raise Exception(
115 "Image size exceeds maximum allowed image size " +
116 "({}B > {}B)".format(image_size, args.max_image_size))
117
David Brazdild623d312019-12-19 16:04:06 +0000118def Main():
119 parser = argparse.ArgumentParser()
120 parser.add_argument("input_elf",
121 help="ELF file to analyze")
122 parser.add_argument("stamp_file",
123 help="file to be touched if successful")
David Brazdila2f45212020-01-20 13:19:31 +0000124 parser.add_argument("--max-image-size",
125 required=False, type=int, default=0,
126 help="maximum allowed image size in bytes")
David Brazdild623d312019-12-19 16:04:06 +0000127 args = parser.parse_args()
128
David Brazdila2f45212020-01-20 13:19:31 +0000129 check_eret_speculation_barrier(args)
130 check_max_image_size(args)
David Brazdild623d312019-12-19 16:04:06 +0000131
132 # Touch `stamp_file`.
133 with open(args.stamp_file, "w"):
134 pass
135
136 return 0
137
138if __name__ == "__main__":
139 sys.exit(Main())