blob: c0482b7ec86c45660dd8d943f0bd9f904942ef02 [file] [log] [blame]
Raef Coles59cf5d82024-12-09 15:41:13 +00001#-------------------------------------------------------------------------------
2# SPDX-FileCopyrightText: Copyright The TrustedFirmware-M Contributors
3#
4# SPDX-License-Identifier: BSD-3-Clause
5#
6#-------------------------------------------------------------------------------
7
8import argparse
9
10import logging
Raef Colescfc31242025-04-04 09:38:47 +010011logger = logging.getLogger("TF-M.{}".format(__name__))
Raef Coles59cf5d82024-12-09 15:41:13 +000012
13from elftools.elf.elffile import ELFFile
14from file_loader import load_bytes_from_file
15
16from c_struct import C_enum
17
18from os.path import isfile
19
20from crypto_conversion_utils import convert_curve_define, convert_hash_define
21
22prefix_sep = ":"
23
24def incompatible_arg(args : argparse.Namespace,
25 arg1 : str,
26 arg2 : str
27 ):
28 assert not (get_arg(args, arg1) and get_arg(args, arg2)), "Incompatible arguments {} and {} cannot both be specified".format(arg1, arg2)
29
30def add_prefixed_argument(parser: argparse.ArgumentParser,
31 arg_name : str,
32 prefix : str = "",
33 **args):
34
35 if "--" + arg_name not in parser._option_string_actions.keys():
36 parser.add_argument("--" + join_prefix(arg_name, prefix), **args)
37
38def _arg_type_enum(arg : str, enum : C_enum):
39 assert arg in enum.dict.keys(), "Invalid enum value {} not in {}".format(arg, list(enum.dict.keys()))
40 return enum.dict[arg]
41
42def arg_type_enum(enum : C_enum):
43 return lambda x: _arg_type_enum(x, enum)
44
45
46def add_prefixed_enum_argument(parser : argparse.ArgumentParser,
47 enum : C_enum,
48 arg_name : str,
49 default : str = None,
50 prefix : str = "",
51 **kwargs):
52
53 if default:
54 assert default in enum.dict.keys()
55
56 return add_prefixed_argument(parser=parser,
57 arg_name = arg_name,
58 type=arg_type_enum(enum),
59 prefix=prefix,
60 default=default,
61 metavar=enum.name,
62 choices=enum.dict.values(),
63 **kwargs)
64
65
66def join_prefix(arg : str, prefix : str):
67 assert(arg)
68
69 if not prefix:
70 return arg
71
72 if prefix_sep not in arg:
73 return prefix + prefix_sep + arg
74 else:
75 #Insert the prefix at the right of current prefixes
76 curr_prefix, arg = arg.rsplit(prefix_sep, 1)
77 return curr_prefix + prefix_sep + prefix + prefix_sep + arg
78
79def is_prefixed(arg : str, prefix : str):
80 return prefix + prefix_sep in arg
81
82def unjoin_prefix(arg : str, prefix : str):
83 if not prefix:
84 return arg
85
86 assert(is_prefixed(arg, prefix))
87
88 return arg.rsplit(prefix + prefix_sep, 1)[1]
89
90def get_arg(args : argparse.Namespace,
91 arg_name : str,
92 prefix : str = "",
93 ):
94 if hasattr(args, join_prefix(arg_name, prefix)):
95 return getattr(args, join_prefix(arg_name, prefix))
96 else:
97 logging.info("Arg {} value not set".format(arg_name))
98 return None
99
100def parse_args_automatically(args : argparse.Namespace,
101 arg_names : [str],
102 prefix : str = "",
103 ) -> dict:
104 return {a: get_arg(args, a, prefix) for a in arg_names if get_arg(args, a, prefix) is not None}
105
106def arg_type_version(arg):
107 assert (len(arg.split(".")) == 3), "Invalid image version format (must be \"x.y.z(+q)?\""
108 return [int(x) for x in arg.replace("+", ".").split(".")]
109
110def _arg_type_elf_section(arg : str,
111 section_name : str,
112 ) -> bytes:
113 if type(section_name) == str:
114 section_name = [section_name]
115
116 out = []
117
118 with ELFFile(open(arg, 'rb')) as elffile:
119 for s in section_name:
120 section = elffile.get_section_by_name(s)
121 if section:
122 out.append(section.data())
123 else:
124 out.append(None)
125 logging.warning("ELF file {} does not contain section {}".format(arg, s))
126 return out
127
128def arg_type_elf_section(section_name : str):
129 return lambda x: _arg_type_elf_section(x, section_name)
130
131def arg_type_elf(arg : str) -> bytes:
132
133 return {"code": code_section.data(), "data": data_section.data() if data_section else None}
134
135def arg_type_filepath(arg : str) -> str:
136 assert isfile(arg), "File {} does not exist".format(arg)
137 return arg
138
139def arg_type_bytes_from_file(arg : str) -> (bytes, bytes):
140 return load_bytes_from_file(arg)
141
142def arg_type_hex(arg : str) -> int:
143 assert(arg)
144 return bytes.fromhex(arg)
145
146def arg_type_bytes(arg : str) -> bytes:
147 try:
148 return arg_type_bytes_from_file(arg)
149 except FileNotFoundError:
150 assert len(arg) % 2 == 0, "Hex values must be a multiple of two characters long"
151 return arg_type_hex(arg.replace("0x", ""))
152
153def arg_type_bytes_output_file(arg : str):
154 return open(arg, "wb")
155
156def arg_type_text_output_file(arg : str):
157 return open(arg, "wt")
158
159def arg_type_hash(arg : str):
160 return convert_hash_define(arg)
161
162def arg_type_curve(arg : str):
163 return convert_curve_define(arg)
164
165def arg_type_bool(arg : str):
166 larg = arg.lower()
167
168 assert larg in ["true", "false", "on", "off"], "Invalid boolean value {}".format(arg)
169
170 return larg in ["true", "on"]
171
172def pre_parse_args(parser : argparse.ArgumentParser,
173 name : str,
174 **kwargs : dict):
175 pre_arg_parser = argparse.ArgumentParser(add_help=False)
176
177 pre_arg_parser.add_argument("--" + name, required=True, **kwargs)
178
179 if "--" + name not in parser._option_string_actions.keys():
180 parser.add_argument("--" + name, required=True, **kwargs)
181
182 parsed, _ = pre_arg_parser.parse_known_args()
183 return getattr(parsed, name)