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 "vdso_wrapper_generator.h"
6
7 #include <algorithm>
8
9 using std::ofstream;
10 using std::string;
11 using std::vector;
12
13 static const string in = " ";
14 static const string inin = in + in;
15
none_apply(const Syscall & sc,const std::vector<CallWrapper * > wrappers)16 static bool none_apply(const Syscall& sc, const std::vector<CallWrapper*> wrappers) {
17 for (const CallWrapper* wrapper : wrappers) {
18 if (wrapper->applies(sc)) {
19 return false;
20 }
21 }
22 return true;
23 }
24
syscall(ofstream & os,const Syscall & sc)25 bool VdsoWrapperGenerator::syscall(ofstream& os, const Syscall& sc) {
26 if (sc.is_vdso() || none_apply(sc, wrappers_)) {
27 // Skip all calls implemented in the VDSO. They're on their own.
28 return os.good();
29 }
30
31 // Writing the wrapper.
32 write_syscall_signature_line(os, sc, wrapper_prefix_, "", " ", false, "");
33 os << " {\n"
34 << in;
35 std::string return_var = write_syscall_return_var(os, sc);
36 pre_call(os, sc);
37 os << inin;
38 // Invoke the actuall syscall.
39 write_syscall_invocation(os, sc, return_var, call_prefix_);
40 post_call(os, sc, return_var);
41
42 if (!return_var.empty()) {
43 os << in << "return " << return_var << ";\n";
44 }
45 os << "}\n\n";
46
47 // Now put the wrapper into the public interface.
48 os << "VDSO_INTERFACE_FUNCTION(zx_" << sc.name << ");\n\n";
49
50 return os.good();
51 }
52
pre_call(ofstream & os,const Syscall & sc) const53 void VdsoWrapperGenerator::pre_call(ofstream& os, const Syscall& sc) const {
54 std::for_each(wrappers_.begin(), wrappers_.end(), [&os, &sc](const CallWrapper* wrapper) {
55 if (wrapper->applies(sc)) {
56 wrapper->preCall(os, sc);
57 }
58 });
59 }
60
post_call(ofstream & os,const Syscall & sc,string return_var) const61 void VdsoWrapperGenerator::post_call(ofstream& os, const Syscall& sc, string return_var) const {
62 std::for_each(wrappers_.rbegin(), wrappers_.rend(), [&os, &sc, &return_var](const CallWrapper* wrapper) {
63 if (wrapper->applies(sc)) {
64 wrapper->postCall(os, sc, return_var);
65 }
66 });
67 }
68
applies(const Syscall & sc) const69 bool TestWrapper::applies(const Syscall& sc) const {
70 return sc.name == "syscall_test_wrapper";
71 }
72
preCall(ofstream & os,const Syscall & sc) const73 void TestWrapper::preCall(ofstream& os, const Syscall& sc) const {
74 os << in << "if (a < 0 || b < 0 || c < 0) return ZX_ERR_INVALID_ARGS;\n";
75 }
76
postCall(ofstream & os,const Syscall & sc,string return_var) const77 void TestWrapper::postCall(ofstream& os, const Syscall& sc, string return_var) const {
78 os << in << "if (" << return_var << " > 50) return ZX_ERR_OUT_OF_RANGE;\n";
79 }
80
applies(const Syscall & sc) const81 bool BlockingRetryWrapper::applies(const Syscall& sc) const {
82 return sc.is_blocking();
83 }
84
preCall(ofstream & os,const Syscall & sc) const85 void BlockingRetryWrapper::preCall(ofstream& os, const Syscall& sc) const {
86 os << in << "do {\n";
87 }
88
postCall(ofstream & os,const Syscall & sc,string return_var) const89 void BlockingRetryWrapper::postCall(
90 ofstream& os, const Syscall& sc, string return_var) const {
91 os << in << "} while (unlikely(" << return_var << " == ZX_ERR_INTERNAL_INTR_RETRY));\n";
92 }
93