| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <algorithm> |
| #include <ctime> |
| |
| #include "generator.h" |
| #include "header_generator.h" |
| #include "vdso_wrapper_generator.h" |
| |
| #include "abigen_generator.h" |
| |
| using std::map; |
| using std::string; |
| using std::vector; |
| |
| const map<string, string> user_attrs = { |
| {"noreturn", "__NO_RETURN"}, |
| {"const", "__CONST"}, |
| {"deprecated", "__DEPRECATE"}, |
| |
| // All vDSO calls are "leaf" in the sense of the GCC attribute. |
| // It just means they can't ever call back into their callers' |
| // own translation unit. No vDSO calls make callbacks at all. |
| {"*", "__LEAF_FN"}, |
| }; |
| |
| const map<string, string> kernel_attrs = { |
| {"noreturn", "__NO_RETURN"}, |
| }; |
| |
| static TestWrapper test_wrapper; |
| static BlockingRetryWrapper blocking_wrapper; |
| static vector<CallWrapper*> wrappers = {&test_wrapper, &blocking_wrapper}; |
| |
| static VdsoWrapperGenerator vdso_wrapper_generator( |
| "_zx_", // wrapper function name |
| "SYSCALL_zx_", // syscall implementation name |
| wrappers); |
| |
| static KernelBranchGenerator kernel_branch; |
| |
| static KernelWrapperGenerator kernel_wrappers( |
| "sys_", // function prefix |
| "wrapper_", // wrapper prefix |
| "ZX_SYS_"); // syscall numbers constant prefix |
| |
| static bool skip_nothing(const Syscall&) { |
| return false; |
| } |
| |
| static bool skip_internal(const Syscall& sc) { |
| return sc.is_internal(); |
| } |
| |
| static bool skip_vdso(const Syscall& sc) { |
| return sc.is_vdso(); |
| } |
| |
| static HeaderGenerator user_header( |
| "extern ", // function prefix |
| { |
| {"zx_", skip_internal}, |
| {"_zx_", skip_internal}, |
| }, |
| "void", // no-args special type |
| false, // wrap pointers |
| user_attrs); |
| |
| static HeaderGenerator vdso_header( |
| "__LOCAL extern ", // function prefix |
| { |
| {"VDSO_zx_", skip_nothing}, |
| {"SYSCALL_zx_", skip_vdso}, |
| }, |
| "void", // no-args special type |
| false, |
| user_attrs); |
| |
| static HeaderGenerator kernel_header( |
| "", |
| { |
| {"sys_", skip_vdso}, |
| }, |
| "", |
| true, |
| kernel_attrs); |
| |
| static VDsoAsmGenerator vdso_asm_generator( |
| "m_syscall", // syscall macro name |
| "zx_", // syscall name prefix |
| wrappers); |
| |
| static SyscallNumbersGenerator syscall_num_generator("#define ZX_SYS_"); |
| |
| static RustBindingGenerator rust_binding_generator; |
| static TraceInfoGenerator trace_generator; |
| static CategoryGenerator category_generator; |
| static JsonGenerator json_generator; |
| |
| const map<string, Generator&> type_to_generator = { |
| // The user header, pure C. |
| {"user-header", user_header}, |
| |
| // The vDSO-internal header, pure C. (VDsoHeaderC) |
| {"vdso-header", vdso_header}, |
| |
| // The kernel header, C++. |
| {"kernel-header", kernel_header}, |
| |
| // The kernel assembly branches and jump table. |
| {"kernel-branch", kernel_branch}, |
| |
| // The kernel C++ wrappers. |
| {"kernel-wrappers", kernel_wrappers}, |
| |
| // The assembly file for x86-64. |
| {"x86-asm", vdso_asm_generator}, |
| |
| // The assembly include file for ARM64. |
| {"arm-asm", vdso_asm_generator}, |
| |
| // A C header defining ZX_SYS_* syscall number macros. |
| {"numbers", syscall_num_generator}, |
| |
| // The trace subsystem data, to be interpreted as an array of structs. |
| {"trace", trace_generator}, |
| |
| // Rust bindings. |
| {"rust", rust_binding_generator}, |
| |
| // vDSO wrappers for additional behaviour in user space. |
| {"vdso-wrappers", vdso_wrapper_generator}, |
| |
| // Category list. |
| {"category", category_generator}, |
| |
| // JSON list of syscalls. |
| {"json", json_generator}, |
| }; |
| |
| const map<string, string> type_to_default_suffix = { |
| {"user-header", ".user.h"}, |
| {"vdso-header", ".vdso.h"}, |
| {"kernel-header", ".kernel.h"}, |
| {"kernel-branch", ".kernel-branch.S"}, |
| {"kernel-wrappers", ".kernel-wrappers.inc"}, |
| {"x86-asm", ".x86-64.S"}, |
| {"arm-asm", ".arm64.S"}, |
| {"numbers", ".syscall-numbers.h"}, |
| {"trace", ".trace.inc"}, |
| {"rust", ".rs"}, |
| {"vdso-wrappers", ".vdso-wrappers.inc"}, |
| {"category", ".category.inc"}, |
| {"json", ".json"}, |
| }; |
| |
| const map<string, string>& get_type_to_default_suffix() { |
| return type_to_default_suffix; |
| } |
| |
| const map<string, Generator&>& get_type_to_generator() { |
| return type_to_generator; |
| } |
| |
| bool AbigenGenerator::AddSyscall(Syscall&& syscall) { |
| if (!syscall.validate()) |
| return false; |
| |
| syscall.requirements = pending_requirements_; |
| pending_requirements_.clear(); |
| |
| syscall.top_description = pending_top_description_; |
| pending_top_description_ = TopDescription(); |
| |
| syscall.assign_index(&next_index_); |
| calls_.emplace_back(std::move(syscall)); |
| return true; |
| } |
| |
| bool AbigenGenerator::Generate(const map<string, string>& type_to_filename) { |
| for (auto& entry : type_to_filename) { |
| if (!generate_one(entry.second, type_to_generator.at(entry.first), entry.first)) |
| return false; |
| } |
| return true; |
| } |
| |
| bool AbigenGenerator::verbose() const { |
| return verbose_; |
| } |
| |
| void AbigenGenerator::AppendRequirement(Requirement&& req) { |
| pending_requirements_.emplace_back(req); |
| } |
| |
| void AbigenGenerator::SetTopDescription(TopDescription&& td) { |
| pending_top_description_ = std::move(td); |
| } |
| |
| bool AbigenGenerator::generate_one( |
| const string& output_file, Generator& generator, const string& type) { |
| std::ofstream ofile; |
| ofile.open(output_file.c_str(), std::ofstream::out); |
| |
| if (!generator.header(ofile)) { |
| print_error("i/o error", output_file); |
| return false; |
| } |
| |
| if (!std::all_of(calls_.begin(), calls_.end(), |
| [&generator, &ofile](const Syscall& sc) { |
| return generator.syscall(ofile, sc); |
| })) { |
| print_error("generation failed", output_file); |
| return false; |
| } |
| |
| if (!generator.footer(ofile)) { |
| print_error("i/o error", output_file); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| void AbigenGenerator::print_error(const char* what, const string& file) { |
| fprintf(stderr, "error: %s for %s\n", what, file.c_str()); |
| } |