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 <algorithm>
6 #include <ctime>
7
8 #include "generator.h"
9 #include "header_generator.h"
10 #include "vdso_wrapper_generator.h"
11
12 #include "abigen_generator.h"
13
14 using std::map;
15 using std::string;
16 using std::vector;
17
18 const map<string, string> user_attrs = {
19 {"noreturn", "__NO_RETURN"},
20 {"const", "__CONST"},
21 {"deprecated", "__DEPRECATE"},
22
23 // All vDSO calls are "leaf" in the sense of the GCC attribute.
24 // It just means they can't ever call back into their callers'
25 // own translation unit. No vDSO calls make callbacks at all.
26 {"*", "__LEAF_FN"},
27 };
28
29 const map<string, string> kernel_attrs = {
30 {"noreturn", "__NO_RETURN"},
31 };
32
33 static TestWrapper test_wrapper;
34 static BlockingRetryWrapper blocking_wrapper;
35 static vector<CallWrapper*> wrappers = {&test_wrapper, &blocking_wrapper};
36
37 static VdsoWrapperGenerator vdso_wrapper_generator(
38 "_zx_", // wrapper function name
39 "SYSCALL_zx_", // syscall implementation name
40 wrappers);
41
42 static KernelBranchGenerator kernel_branch;
43
44 static KernelWrapperGenerator kernel_wrappers(
45 "sys_", // function prefix
46 "wrapper_", // wrapper prefix
47 "ZX_SYS_"); // syscall numbers constant prefix
48
skip_nothing(const Syscall &)49 static bool skip_nothing(const Syscall&) {
50 return false;
51 }
52
skip_internal(const Syscall & sc)53 static bool skip_internal(const Syscall& sc) {
54 return sc.is_internal();
55 }
56
skip_vdso(const Syscall & sc)57 static bool skip_vdso(const Syscall& sc) {
58 return sc.is_vdso();
59 }
60
61 static HeaderGenerator user_header(
62 "extern ", // function prefix
63 {
64 {"zx_", skip_internal},
65 {"_zx_", skip_internal},
66 },
67 "void", // no-args special type
68 false, // wrap pointers
69 user_attrs);
70
71 static HeaderGenerator vdso_header(
72 "__LOCAL extern ", // function prefix
73 {
74 {"VDSO_zx_", skip_nothing},
75 {"SYSCALL_zx_", skip_vdso},
76 },
77 "void", // no-args special type
78 false,
79 user_attrs);
80
81 static HeaderGenerator kernel_header(
82 "",
83 {
84 {"sys_", skip_vdso},
85 },
86 "",
87 true,
88 kernel_attrs);
89
90 static VDsoAsmGenerator vdso_asm_generator(
91 "m_syscall", // syscall macro name
92 "zx_", // syscall name prefix
93 wrappers);
94
95 static SyscallNumbersGenerator syscall_num_generator("#define ZX_SYS_");
96
97 static RustBindingGenerator rust_binding_generator;
98 static TraceInfoGenerator trace_generator;
99 static CategoryGenerator category_generator;
100 static JsonGenerator json_generator;
101
102 const map<string, Generator&> type_to_generator = {
103 // The user header, pure C.
104 {"user-header", user_header},
105
106 // The vDSO-internal header, pure C. (VDsoHeaderC)
107 {"vdso-header", vdso_header},
108
109 // The kernel header, C++.
110 {"kernel-header", kernel_header},
111
112 // The kernel assembly branches and jump table.
113 {"kernel-branch", kernel_branch},
114
115 // The kernel C++ wrappers.
116 {"kernel-wrappers", kernel_wrappers},
117
118 // The assembly file for x86-64.
119 {"x86-asm", vdso_asm_generator},
120
121 // The assembly include file for ARM64.
122 {"arm-asm", vdso_asm_generator},
123
124 // A C header defining ZX_SYS_* syscall number macros.
125 {"numbers", syscall_num_generator},
126
127 // The trace subsystem data, to be interpreted as an array of structs.
128 {"trace", trace_generator},
129
130 // Rust bindings.
131 {"rust", rust_binding_generator},
132
133 // vDSO wrappers for additional behaviour in user space.
134 {"vdso-wrappers", vdso_wrapper_generator},
135
136 // Category list.
137 {"category", category_generator},
138
139 // JSON list of syscalls.
140 {"json", json_generator},
141 };
142
143 const map<string, string> type_to_default_suffix = {
144 {"user-header", ".user.h"},
145 {"vdso-header", ".vdso.h"},
146 {"kernel-header", ".kernel.h"},
147 {"kernel-branch", ".kernel-branch.S"},
148 {"kernel-wrappers", ".kernel-wrappers.inc"},
149 {"x86-asm", ".x86-64.S"},
150 {"arm-asm", ".arm64.S"},
151 {"numbers", ".syscall-numbers.h"},
152 {"trace", ".trace.inc"},
153 {"rust", ".rs"},
154 {"vdso-wrappers", ".vdso-wrappers.inc"},
155 {"category", ".category.inc"},
156 {"json", ".json"},
157 };
158
get_type_to_default_suffix()159 const map<string, string>& get_type_to_default_suffix() {
160 return type_to_default_suffix;
161 }
162
get_type_to_generator()163 const map<string, Generator&>& get_type_to_generator() {
164 return type_to_generator;
165 }
166
AddSyscall(Syscall && syscall)167 bool AbigenGenerator::AddSyscall(Syscall&& syscall) {
168 if (!syscall.validate())
169 return false;
170
171 syscall.requirements = pending_requirements_;
172 pending_requirements_.clear();
173
174 syscall.top_description = pending_top_description_;
175 pending_top_description_ = TopDescription();
176
177 syscall.assign_index(&next_index_);
178 calls_.emplace_back(std::move(syscall));
179 return true;
180 }
181
Generate(const map<string,string> & type_to_filename)182 bool AbigenGenerator::Generate(const map<string, string>& type_to_filename) {
183 for (auto& entry : type_to_filename) {
184 if (!generate_one(entry.second, type_to_generator.at(entry.first), entry.first))
185 return false;
186 }
187 return true;
188 }
189
verbose() const190 bool AbigenGenerator::verbose() const {
191 return verbose_;
192 }
193
AppendRequirement(Requirement && req)194 void AbigenGenerator::AppendRequirement(Requirement&& req) {
195 pending_requirements_.emplace_back(req);
196 }
197
SetTopDescription(TopDescription && td)198 void AbigenGenerator::SetTopDescription(TopDescription&& td) {
199 pending_top_description_ = std::move(td);
200 }
201
generate_one(const string & output_file,Generator & generator,const string & type)202 bool AbigenGenerator::generate_one(
203 const string& output_file, Generator& generator, const string& type) {
204 std::ofstream ofile;
205 ofile.open(output_file.c_str(), std::ofstream::out);
206
207 if (!generator.header(ofile)) {
208 print_error("i/o error", output_file);
209 return false;
210 }
211
212 if (!std::all_of(calls_.begin(), calls_.end(),
213 [&generator, &ofile](const Syscall& sc) {
214 return generator.syscall(ofile, sc);
215 })) {
216 print_error("generation failed", output_file);
217 return false;
218 }
219
220 if (!generator.footer(ofile)) {
221 print_error("i/o error", output_file);
222 return false;
223 }
224
225 return true;
226 }
227
print_error(const char * what,const string & file)228 void AbigenGenerator::print_error(const char* what, const string& file) {
229 fprintf(stderr, "error: %s for %s\n", what, file.c_str());
230 }
231