1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <ctime>
6 #include <fstream>
7 
8 #include "generator.h"
9 
10 using std::ofstream;
11 using std::string;
12 
13 static constexpr char kAuthors[] = "The Fuchsia Authors";
14 static constexpr char kWrapMacro[] = "ZX_SYSCALL_PARAM_ATTR";
15 static constexpr char kDefaultHandleAnnotation[] = "handle_use";
16 bool is_identifier_keyword(const string& iden);
17 
header(ofstream & os)18 bool Generator::header(ofstream& os) {
19     auto t = std::time(nullptr);
20     auto ltime = std::localtime(&t);
21 
22     os << "// Copyright " << ltime->tm_year + 1900
23        << " " << kAuthors << ". All rights reserved.\n";
24     os << "// This is a GENERATED file, see //zircon/system/host/abigen.\n";
25     os << "// The license governing this file can be found in the LICENSE file.\n\n";
26 
27     return os.good();
28 }
29 
footer(ofstream & os)30 bool Generator::footer(ofstream& os) {
31     os << "\n";
32     return os.good();
33 }
34 
syscall(ofstream & os,const Syscall & sc)35 bool VDsoAsmGenerator::syscall(ofstream& os, const Syscall& sc) {
36     if (!sc.is_vdso()) {
37         bool is_public = !sc.is_internal();
38         for (const CallWrapper* wrapper : wrappers_) {
39             if (wrapper->applies(sc)) {
40                 is_public = false;
41                 break;
42             }
43         }
44 
45         // m_syscall name, syscall_num, nargs
46         os << syscall_macro_
47            << " " << name_prefix_ << sc.name
48            << " " << sc.index
49            << " " << sc.num_kernel_args()
50            << " " << (is_public ? 1 : 0)
51            << "\n";
52     }
53     return os.good();
54 }
55 
header(ofstream & os)56 bool KernelBranchGenerator::header(ofstream& os) {
57     if (!Generator::header(os))
58         return false;
59 
60     os << "start_syscall_dispatch\n";
61     return os.good();
62 }
63 
syscall(ofstream & os,const Syscall & sc)64 bool KernelBranchGenerator::syscall(ofstream& os, const Syscall& sc) {
65     if (sc.is_vdso()) {
66         return os.good();
67     }
68     os << "syscall_dispatch " << sc.num_kernel_args() << " " << sc.name << "\n";
69     return os.good();
70 }
71 
syscall(ofstream & os,const Syscall & sc)72 bool SyscallNumbersGenerator::syscall(ofstream& os, const Syscall& sc) {
73     if (sc.is_vdso())
74         return true;
75 
76     num_calls_++;
77     os << define_prefix_ << sc.name << " " << sc.index << "\n";
78     return os.good();
79 }
80 
footer(ofstream & os)81 bool SyscallNumbersGenerator::footer(ofstream& os) {
82     os << define_prefix_ << "COUNT " << num_calls_ << "\n";
83     return os.good();
84 }
85 
syscall(ofstream & os,const Syscall & sc)86 bool TraceInfoGenerator::syscall(ofstream& os, const Syscall& sc) {
87     if (sc.is_vdso())
88         return true;
89 
90     // Can be injected as an array of structs or into a tuple-like C++ container.
91     os << "{" << sc.index << ", " << sc.num_kernel_args() << ", "
92        << '"' << sc.name << "\"},\n";
93 
94     return os.good();
95 }
96 
syscall(ofstream & os,const Syscall & sc)97 bool CategoryGenerator::syscall(ofstream& os, const Syscall& sc) {
98     for (const auto& attr : sc.attributes) {
99         if (attr != "*" && attr != "internal")
100             category_map_[attr].push_back(&sc.name);
101     }
102     return true;
103 }
104 
footer(ofstream & os)105 bool CategoryGenerator::footer(ofstream& os) {
106     for (const auto& category : category_map_) {
107         os << "\n#define HAVE_SYSCALL_CATEGORY_" << category.first << " 1\n";
108         os << "SYSCALL_CATEGORY_BEGIN(" << category.first << ")\n";
109 
110         for (auto sc : category.second)
111             os << "    SYSCALL_IN_CATEGORY(" << *sc << ")\n";
112 
113         os << "SYSCALL_CATEGORY_END(" << category.first << ")\n";
114     }
115     return os.good();
116 }
117 
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)118 void write_syscall_signature_line(ofstream& os, const Syscall& sc, string name_prefix,
119                                   string before_args, string inter_arg,
120                                   bool wrap_pointers_with_user_ptr, string no_args_type) {
121     auto syscall_name = name_prefix + sc.name;
122 
123     // writes "[return-type] prefix_[syscall-name]("
124     os << sc.return_type() << " " << syscall_name << "(";
125 
126     // Writes all arguments.
127     os << before_args;
128     bool first = true;
129     sc.for_each_kernel_arg([&](const TypeSpec& arg) {
130         if (!first) {
131             os << inter_arg;
132         }
133         first = false;
134         write_argument_annotation(os, arg);
135         os << arg.as_cpp_declaration(wrap_pointers_with_user_ptr) << ",";
136     });
137 
138     if (sc.num_kernel_args() > 0) {
139         // remove the comma.
140         os.seekp(-1, std::ios_base::end);
141     } else {
142         os << no_args_type;
143     }
144 
145     os << ")";
146 }
147 
write_syscall_return_var(ofstream & os,const Syscall & sc)148 string write_syscall_return_var(ofstream& os, const Syscall& sc) {
149     string return_var = sc.is_void_return() ? "" : "ret";
150     if (!sc.is_void_return()) {
151         os << sc.return_type() << " " << return_var << ";\n";
152     }
153     return return_var;
154 }
155 
write_syscall_invocation(ofstream & os,const Syscall & sc,const string & return_var,const string & name_prefix)156 void write_syscall_invocation(ofstream& os, const Syscall& sc,
157                               const string& return_var, const string& name_prefix) {
158     if (!return_var.empty()) {
159         os << return_var << " = ";
160     }
161 
162     os << name_prefix << sc.name << "(";
163 
164     // Writes all arguments.
165     sc.for_each_kernel_arg([&](const TypeSpec& arg) {
166         os << arg.name << ", ";
167     });
168 
169     if (sc.num_kernel_args() > 0) {
170         // remove the comma and space.
171         os.seekp(-2, std::ios_base::end);
172     }
173 
174     os << ");\n";
175 }
176 
write_argument_annotation(std::ofstream & os,const TypeSpec & arg)177 void write_argument_annotation(std::ofstream& os, const TypeSpec& arg) {
178     bool has_annotation = false;
179     for (const auto& a : arg.attributes) {
180         if (!a.empty() && !is_identifier_keyword(a)) {
181             has_annotation = true;
182             os << kWrapMacro << "(" << a << ") ";
183         }
184     }
185     // If arg type is a handle (not an array) and no annotation is present, use default annotation
186     if (!has_annotation && arg.type == "zx_handle_t" && arg.arr_spec == nullptr) {
187         os << kWrapMacro << "(" << kDefaultHandleAnnotation << ") ";
188     }
189 }
190