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