blob: 416cb3c232ece418268d3f513ace3c87a44c4b89 [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
HEADER = """// Copyright %s 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-embedding.py.
// DO NOT EDIT.
""" % datetime.today().year
ASM_FILE = string.Template(
HEADER + """
#include <lib/arch/asm.h>
.text
$body
""")
CPP_FILE = string.Template(
HEADER + """
#include <cstddef>
#include <span>
#include <string_view>
using namespace std::literals;
$externs
// Looks a code patching alternative up by name, returning its raw, binary
// contents if known or else returning an empty span.
std::span<const std::byte> GetPatchAlternative(std::string_view name) {
$function_body
}
""")
def main():
parser = argparse.ArgumentParser(
description=
"Creates an object file defining a function for looking up hermetic alternative blobs by name"
)
parser.add_argument("--name", help="The name of the stub function")
# Metadata contents is expected to be in the following format:
#
# [
# { entry: "memset_fast", path: "build/dir/relative/path/to/x.bin" },
# { entry: "memset_slow", path: "build/dir/relative/path/to/y.bin" }
# ]
parser.add_argument(
"--metadata-file",
metavar="FILE",
help="a JSON file of hermetic patch alternative metadata")
parser.add_argument(
"--depfile", metavar="FILE", help="A dependencies file to write to")
parser.add_argument(
"--asm-outfile",
metavar="FILE",
help=
".S file that defines symbols giving hermetic patch alternative content."
)
parser.add_argument(
"--cpp-outfile",
metavar="FILE",
help=
".cc file that defines a function for looking up hermetic patch alternative content by name"
)
args = parser.parse_args()
with open(args.metadata_file, "r") as metadata_file:
metadata = json.load(metadata_file)
deps = []
asm_body = []
cpp_externs = []
cpp_function_body = []
for entry in metadata:
name = entry["name"]
path = entry["path"]
alternative_start = "HERMETIC_ALTERNATIVE_START_%s" % name
alternative_stop = "HERMETIC_ALTERNATIVE_STOP_%s" % name
deps.append(path)
# Defines the symbols for the beginnings and ends of each alternative.
asm_body.extend(
[
".object %s, data, global" % alternative_start,
".incbin \"%s\"" % path,
".label %s, global" % alternative_stop,
".end_object",
"",
])
# The .cc file will declare the beginnings and ends as extern - and
# further define a function for looking up an alternative by name.
cpp_externs.extend(
[
"extern \"C\" const std::byte %s[];" % alternative_start,
"extern \"C\" const std::byte %s[];" % alternative_stop,
])
cpp_function_body.extend(
[
" if (name == \"%s\"sv) {" % name,
" return {%s, static_cast<size_t>(%s - %s)};" %
(alternative_start, alternative_stop, alternative_start),
" }",
])
# Return an empty span if we were unable to find a match.
cpp_function_body.append(" return {};")
with open(args.depfile, "w") as depfile:
dep_list = " ".join(sorted(deps))
depfile.write("%s: %s\n" % (args.asm_outfile, dep_list))
depfile.write("%s: %s\n" % (args.cpp_outfile, dep_list))
with open(args.asm_outfile, "w") as outfile:
outfile.write(ASM_FILE.substitute(body="\n".join(asm_body)))
with open(args.cpp_outfile, "w") as outfile:
outfile.write(
CPP_FILE.substitute(
externs="\n".join(cpp_externs),
function_body="\n".join(cpp_function_body)))
if __name__ == "__main__":
main()