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
14using std::string;
15using std::map;
16using std::vector;
17
18const 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
29const map<string, string> kernel_attrs = {
30    {"noreturn", "__NO_RETURN"},
31};
32
33static TestWrapper test_wrapper;
34static BlockingRetryWrapper blocking_wrapper;
35static vector<CallWrapper*> wrappers = {&test_wrapper, &blocking_wrapper};
36
37static VdsoWrapperGenerator vdso_wrapper_generator(
38    "_zx_",        // wrapper function name
39    "SYSCALL_zx_", // syscall implementation name
40    wrappers);
41
42static KernelBranchGenerator kernel_branch;
43
44static KernelWrapperGenerator kernel_wrappers(
45    "sys_",     // function prefix
46    "wrapper_", // wrapper prefix
47    "ZX_SYS_"); // syscall numbers constant prefix
48
49static bool skip_nothing(const Syscall&) {
50    return false;
51}
52
53static bool skip_internal(const Syscall& sc) {
54    return sc.is_internal();
55}
56
57static bool skip_vdso(const Syscall& sc) {
58    return sc.is_vdso();
59}
60
61static 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
71static 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
81static HeaderGenerator kernel_header(
82    "",
83    {
84        {"sys_", skip_vdso},
85    },
86    "",
87    true,
88    kernel_attrs);
89
90static VDsoAsmGenerator vdso_asm_generator(
91    "m_syscall", // syscall macro name
92    "zx_",       // syscall name prefix
93    wrappers);
94
95static SyscallNumbersGenerator syscall_num_generator("#define ZX_SYS_");
96
97static RustBindingGenerator rust_binding_generator;
98static TraceInfoGenerator trace_generator;
99static CategoryGenerator category_generator;
100static JsonGenerator json_generator;
101
102const 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
143const 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
159const map<string, string>& get_type_to_default_suffix() {
160    return type_to_default_suffix;
161}
162
163const map<string, Generator&>& get_type_to_generator() {
164    return type_to_generator;
165}
166
167bool AbigenGenerator::AddSyscall(Syscall&& syscall) {
168    if (!syscall.validate())
169        return false;
170    syscall.assign_index(&next_index_);
171    calls_.emplace_back(std::move(syscall));
172    return true;
173}
174
175bool AbigenGenerator::Generate(const map<string, string>& type_to_filename) {
176    for (auto& entry : type_to_filename) {
177        if (!generate_one(entry.second, type_to_generator.at(entry.first), entry.first))
178            return false;
179    }
180    return true;
181}
182
183bool AbigenGenerator::verbose() const {
184    return verbose_;
185}
186
187bool AbigenGenerator::generate_one(
188    const string& output_file, Generator& generator, const string& type) {
189    std::ofstream ofile;
190    ofile.open(output_file.c_str(), std::ofstream::out);
191
192    if (!generator.header(ofile)) {
193        print_error("i/o error", output_file);
194        return false;
195    }
196
197    if (!std::all_of(calls_.begin(), calls_.end(),
198                     [&generator, &ofile](const Syscall& sc) {
199                         return generator.syscall(ofile, sc);
200                     })) {
201        print_error("generation failed", output_file);
202        return false;
203    }
204
205    if (!generator.footer(ofile)) {
206        print_error("i/o error", output_file);
207        return false;
208    }
209
210    return true;
211}
212
213void AbigenGenerator::print_error(const char* what, const string& file) {
214    fprintf(stderr, "error: %s for %s\n", what, file.c_str());
215}
216