blob: 45395ccda285b56a13b95c0514da79eafee8e578 [file] [log] [blame]
#!/usr/bin/env python3.8
# Copyright 2021 The Fuchsia Authors
#
# Use of this source code is governed by a MIT-style
# license that can be found in the LICENSE file or at
# https://opensource.org/licenses/MIT
import argparse
import json
import os
import string
from datetime import datetime
STUB_CONTENTS = string.Template(
"""// Copyright $year The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT
// GENERATED BY //zircon/kernel/lib/code-patching/hermetic-stub.py.
// DO NOT EDIT.
#include <lib/arch/asm.h>
#include <lib/code-patching/asm.h>
#include <$header> // Defines $case_id.
.text
.function $function_name, global
.code_patching.blob $size, $case_id, "$default"
.end_function
""")
ALIAS = string.Template(
"""
.weak $alias
.hidden $alias
$alias = $function_name
""")
def main():
parser = argparse.ArgumentParser(
description=
"Creates an assembly file with a single stub functon to be later patched"
)
parser.add_argument("--name", help="The name of the stub function")
parser.add_argument(
"--header", help="A header containing patch case ID constants")
parser.add_argument(
"--metadata-file",
metavar="FILE",
help="a JSON file of hermetic patch alternative metadata")
parser.add_argument(
"--aliases",
type=str,
action="append",
help="Symbol names to alias to the function as",
default=[])
# TODO(fxbug.dev/67615): Remove this option once code patching happens
# within physboot; at this point, pre-patched, trap-filled code will not be
# executed before it is patched.
parser.add_argument(
"--default",
help=
"The name of a hermetic patch alternative to default to instead of trap fill",
)
parser.add_argument(
"--depfile", metavar="FILE", help="A dependencies file to write to")
parser.add_argument(
"--outfile", metavar="FILE", help="The resulting stub file")
args = parser.parse_args()
with open(args.metadata_file, "r") as metadata_file:
metadata = json.load(metadata_file)
default_alternative = None
max_size = 0
alternatives = []
for entry in metadata:
alternative = entry["path"]
alternatives.append(alternative)
max_size = max(max_size, os.path.getsize(alternative))
if entry["name"] == args.default:
default_alternative = alternative
assert args.default is None or default_alternative is not None, \
"alternative %s not found among those in %s" % (args.default, args.metadata_file)
with open(args.depfile, "w") as depfile:
depfile.write(
"%s: %s\n" % (args.outfile, " ".join(sorted(alternatives))))
with open(args.outfile, "w") as stub:
stub.write(
STUB_CONTENTS.substitute(
year=datetime.today().year,
header=args.header,
function_name=args.name,
# Per the expectations of code_patching_hermetic_stub()'s
# `case_id_header` parameter.
case_id="CASE_ID_%s" % args.name.upper(),
default=default_alternative or "",
size=max_size,
))
for alias in args.aliases:
stub.write(ALIAS.substitute(alias=alias, function_name=args.name))
if __name__ == "__main__":
main()