blob: 2749dbd3f464365ddfed7d876619345050e84527 [file] [log] [blame]
// 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 <ctime>
#include <fstream>
#include "generator.h"
using std::ofstream;
using std::string;
static constexpr char kAuthors[] = "The Fuchsia Authors";
static constexpr char kWrapMacro[] = "ZX_SYSCALL_PARAM_ATTR";
static constexpr char kDefaultHandleAnnotation[] = "handle_use";
bool is_identifier_keyword(const string& iden);
bool Generator::header(ofstream& os) {
auto t = std::time(nullptr);
auto ltime = std::localtime(&t);
os << "// Copyright " << ltime->tm_year + 1900
<< " " << kAuthors << ". All rights reserved.\n";
os << "// This is a GENERATED file, see //zircon/system/host/abigen.\n";
os << "// The license governing this file can be found in the LICENSE file.\n\n";
return os.good();
}
bool Generator::footer(ofstream& os) {
os << "\n";
return os.good();
}
bool VDsoAsmGenerator::syscall(ofstream& os, const Syscall& sc) {
if (!sc.is_vdso()) {
bool is_public = !sc.is_internal();
for (const CallWrapper* wrapper : wrappers_) {
if (wrapper->applies(sc)) {
is_public = false;
break;
}
}
// m_syscall name, syscall_num, nargs
os << syscall_macro_
<< " " << name_prefix_ << sc.name
<< " " << sc.index
<< " " << sc.num_kernel_args()
<< " " << (is_public ? 1 : 0)
<< "\n";
}
return os.good();
}
bool KernelBranchGenerator::header(ofstream& os) {
if (!Generator::header(os))
return false;
os << "start_syscall_dispatch\n";
return os.good();
}
bool KernelBranchGenerator::syscall(ofstream& os, const Syscall& sc) {
if (sc.is_vdso()) {
return os.good();
}
os << "syscall_dispatch " << sc.num_kernel_args() << " " << sc.name << "\n";
return os.good();
}
bool SyscallNumbersGenerator::syscall(ofstream& os, const Syscall& sc) {
if (sc.is_vdso())
return true;
num_calls_++;
os << define_prefix_ << sc.name << " " << sc.index << "\n";
return os.good();
}
bool SyscallNumbersGenerator::footer(ofstream& os) {
os << define_prefix_ << "COUNT " << num_calls_ << "\n";
return os.good();
}
bool TraceInfoGenerator::syscall(ofstream& os, const Syscall& sc) {
if (sc.is_vdso())
return true;
// Can be injected as an array of structs or into a tuple-like C++ container.
os << "{" << sc.index << ", " << sc.num_kernel_args() << ", "
<< '"' << sc.name << "\"},\n";
return os.good();
}
bool CategoryGenerator::syscall(ofstream& os, const Syscall& sc) {
for (const auto& attr : sc.attributes) {
if (attr != "*" && attr != "internal")
category_map_[attr].push_back(&sc.name);
}
return true;
}
bool CategoryGenerator::footer(ofstream& os) {
for (const auto& category : category_map_) {
os << "\n#define HAVE_SYSCALL_CATEGORY_" << category.first << " 1\n";
os << "SYSCALL_CATEGORY_BEGIN(" << category.first << ")\n";
for (auto sc : category.second)
os << " SYSCALL_IN_CATEGORY(" << *sc << ")\n";
os << "SYSCALL_CATEGORY_END(" << category.first << ")\n";
}
return os.good();
}
void write_syscall_signature_line(ofstream& os, const Syscall& sc, string name_prefix,
string before_args, string inter_arg,
bool wrap_pointers_with_user_ptr, string no_args_type) {
auto syscall_name = name_prefix + sc.name;
// writes "[return-type] prefix_[syscall-name]("
os << sc.return_type() << " " << syscall_name << "(";
// Writes all arguments.
os << before_args;
bool first = true;
sc.for_each_kernel_arg([&](const TypeSpec& arg) {
if (!first) {
os << inter_arg;
}
first = false;
write_argument_annotation(os, arg);
os << arg.as_cpp_declaration(wrap_pointers_with_user_ptr) << ",";
});
if (sc.num_kernel_args() > 0) {
// remove the comma.
os.seekp(-1, std::ios_base::end);
} else {
os << no_args_type;
}
os << ")";
}
string write_syscall_return_var(ofstream& os, const Syscall& sc) {
string return_var = sc.is_void_return() ? "" : "ret";
if (!sc.is_void_return()) {
os << sc.return_type() << " " << return_var << ";\n";
}
return return_var;
}
void write_syscall_invocation(ofstream& os, const Syscall& sc,
const string& return_var, const string& name_prefix) {
if (!return_var.empty()) {
os << return_var << " = ";
}
os << name_prefix << sc.name << "(";
// Writes all arguments.
sc.for_each_kernel_arg([&](const TypeSpec& arg) {
os << arg.name << ", ";
});
if (sc.num_kernel_args() > 0) {
// remove the comma and space.
os.seekp(-2, std::ios_base::end);
}
os << ");\n";
}
void write_argument_annotation(std::ofstream& os, const TypeSpec& arg) {
bool has_annotation = false;
for (const auto& a : arg.attributes) {
if (!a.empty() && !is_identifier_keyword(a)) {
has_annotation = true;
os << kWrapMacro << "(" << a << ") ";
}
}
// If arg type is a handle (not an array) and no annotation is present, use default annotation
if (!has_annotation && arg.type == "zx_handle_t" && arg.arr_spec == nullptr) {
os << kWrapMacro << "(" << kDefaultHandleAnnotation << ") ";
}
}