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