blob: 6394cb1bfe8be975ae2f66ea61265e973ae83618 [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#
Andrew Walbrane959ec12020-06-17 15:01:09 +01005# Use of this source code is governed by a BSD-style
6# license that can be found in the LICENSE file or at
7# https://opensource.org/licenses/BSD-3-Clause.
David Brazdild623d312019-12-19 16:04:06 +00008
David Brazdild623d312019-12-19 16:04:06 +00009"""Check ELF file for assembly-level regressions.
10
11Objdumps the given ELF file and detects known assembly patterns, checking for
12regressions on bugs such as CPU erratas. Throws an exception if a broken pattern
13is detected.
14"""
15
16import argparse
17import os
18import re
19import subprocess
20import sys
21
Olivier Deprez9fa36962021-09-20 14:32:14 +010022OBJDUMP = "llvm-objdump"
23NM = "llvm-nm"
David Brazdild623d312019-12-19 16:04:06 +000024
David Brazdila2f45212020-01-20 13:19:31 +000025def check_eret_speculation_barrier(args):
David Brazdild623d312019-12-19 16:04:06 +000026 """
27 Some ARM64 CPUs speculatively execute instructions after ERET.
28 Check that every ERET is followed by DSB NSH and ISB.
29 """
David Brazdila2f45212020-01-20 13:19:31 +000030
31 objdump_stdout = subprocess\
32 .check_output([ OBJDUMP, "-d", args.input_elf ])\
33 .decode("utf-8")\
34 .splitlines()
35
David Brazdild623d312019-12-19 16:04:06 +000036 found_eret = False
37
38 STATE_DEFAULT = 1
39 STATE_EXPECT_DSB_NSH = 2
40 STATE_EXPECT_ISB = 3
41
42 REGEX_ERET = re.compile(r"^\s*[0-9a-f]+:\s*e0 03 9f d6\s+eret$")
43 REGEX_DSB_NSH = re.compile(r"^\s*[0-9a-f]+:\s*9f 37 03 d5\s*dsb\s+nsh$")
44 REGEX_ISB = re.compile(r"^\s*[0-9a-f]+:\s*df 3f 03 d5\s+isb$")
45
46 state = STATE_DEFAULT
47 for line in objdump_stdout:
48 if state == STATE_DEFAULT:
49 if re.match(REGEX_ERET, line):
50 found_eret = True
51 state = STATE_EXPECT_DSB_NSH
52 elif state == STATE_EXPECT_DSB_NSH:
53 if re.match(REGEX_DSB_NSH, line):
54 state = STATE_EXPECT_ISB
55 else:
56 raise Exception("ERET not followed by DSB NSH")
57 elif state == STATE_EXPECT_ISB:
58 if re.match(REGEX_ISB, line):
59 state = STATE_DEFAULT
60 else:
61 raise Exception("ERET not followed by ISB")
62
63 # Ensure that at least one instance was found, otherwise the regexes are
64 # probably wrong.
65 if not found_eret:
66 raise Exception("Could not find any ERET instructions")
67
David Brazdila2f45212020-01-20 13:19:31 +000068def check_max_image_size(args):
69 """
70 Check that the ELF's effective image size does not exceed maximum
71 allowed image size, if specified in command-line arguments.
72 """
73
74 if args.max_image_size <= 0:
75 return
76
77 nm_stdout = subprocess\
78 .check_output([ NM, args.input_elf ])\
79 .decode("utf-8")\
80 .splitlines()
81
82 COLUMN_COUNT = 3
83 COLUMN_IDX_VALUE = 0
84 COLUMN_IDX_TYPE = 1
85 COLUMN_IDX_NAME = 2
86
87 image_size = None
88 for line in nm_stdout:
89 line = line.split()
90 if len(line) != COLUMN_COUNT:
91 raise Exception(
92 "Unexpected number of columns in NM output")
93
94 if line[COLUMN_IDX_NAME] == "image_size":
95 if line[COLUMN_IDX_TYPE] != "A":
96 raise Exception(
97 "Unexpected type of image_size symbol")
98 image_size = int(line[COLUMN_IDX_VALUE], 16)
99 break
100
101 if image_size is None:
102 raise Exception("Could not find value of image_size symbol")
103 elif image_size > args.max_image_size:
104 raise Exception(
105 "Image size exceeds maximum allowed image size " +
106 "({}B > {}B)".format(image_size, args.max_image_size))
107
David Brazdild623d312019-12-19 16:04:06 +0000108def Main():
109 parser = argparse.ArgumentParser()
110 parser.add_argument("input_elf",
111 help="ELF file to analyze")
112 parser.add_argument("stamp_file",
113 help="file to be touched if successful")
David Brazdila2f45212020-01-20 13:19:31 +0000114 parser.add_argument("--max-image-size",
115 required=False, type=int, default=0,
116 help="maximum allowed image size in bytes")
David Brazdild623d312019-12-19 16:04:06 +0000117 args = parser.parse_args()
118
David Brazdila2f45212020-01-20 13:19:31 +0000119 check_eret_speculation_barrier(args)
120 check_max_image_size(args)
David Brazdild623d312019-12-19 16:04:06 +0000121
122 # Touch `stamp_file`.
123 with open(args.stamp_file, "w"):
124 pass
125
126 return 0
127
128if __name__ == "__main__":
129 sys.exit(Main())