| // Copyright 2017 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "vdso_wrapper_generator.h" |
| |
| #include <algorithm> |
| |
| using std::ofstream; |
| using std::string; |
| using std::vector; |
| |
| static const string in = " "; |
| static const string inin = in + in; |
| |
| static bool none_apply(const Syscall& sc, const std::vector<CallWrapper*> wrappers) { |
| for (const CallWrapper* wrapper : wrappers) { |
| if (wrapper->applies(sc)) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| bool VdsoWrapperGenerator::syscall(ofstream& os, const Syscall& sc) { |
| if (sc.is_vdso() || none_apply(sc, wrappers_)) { |
| // Skip all calls implemented in the VDSO. They're on their own. |
| return os.good(); |
| } |
| |
| // Writing the wrapper. |
| write_syscall_signature_line(os, sc, wrapper_prefix_, "", " ", false, ""); |
| os << " {\n" |
| << in; |
| std::string return_var = write_syscall_return_var(os, sc); |
| pre_call(os, sc); |
| os << inin; |
| // Invoke the actuall syscall. |
| write_syscall_invocation(os, sc, return_var, call_prefix_); |
| post_call(os, sc, return_var); |
| |
| if (!return_var.empty()) { |
| os << in << "return " << return_var << ";\n"; |
| } |
| os << "}\n\n"; |
| |
| // Now put the wrapper into the public interface. |
| os << "VDSO_INTERFACE_FUNCTION(zx_" << sc.name << ");\n\n"; |
| |
| return os.good(); |
| } |
| |
| void VdsoWrapperGenerator::pre_call(ofstream& os, const Syscall& sc) const { |
| std::for_each(wrappers_.begin(), wrappers_.end(), [&os, &sc](const CallWrapper* wrapper) { |
| if (wrapper->applies(sc)) { |
| wrapper->preCall(os, sc); |
| } |
| }); |
| } |
| |
| void VdsoWrapperGenerator::post_call(ofstream& os, const Syscall& sc, string return_var) const { |
| std::for_each(wrappers_.rbegin(), wrappers_.rend(), [&os, &sc, &return_var](const CallWrapper* wrapper) { |
| if (wrapper->applies(sc)) { |
| wrapper->postCall(os, sc, return_var); |
| } |
| }); |
| } |
| |
| bool TestWrapper::applies(const Syscall& sc) const { |
| return sc.name == "syscall_test_wrapper"; |
| } |
| |
| void TestWrapper::preCall(ofstream& os, const Syscall& sc) const { |
| os << in << "if (a < 0 || b < 0 || c < 0) return ZX_ERR_INVALID_ARGS;\n"; |
| } |
| |
| void TestWrapper::postCall(ofstream& os, const Syscall& sc, string return_var) const { |
| os << in << "if (" << return_var << " > 50) return ZX_ERR_OUT_OF_RANGE;\n"; |
| } |
| |
| bool BlockingRetryWrapper::applies(const Syscall& sc) const { |
| return sc.is_blocking(); |
| } |
| |
| void BlockingRetryWrapper::preCall(ofstream& os, const Syscall& sc) const { |
| os << in << "do {\n"; |
| } |
| |
| void BlockingRetryWrapper::postCall( |
| ofstream& os, const Syscall& sc, string return_var) const { |
| os << in << "} while (unlikely(" << return_var << " == ZX_ERR_INTERNAL_INTR_RETRY));\n"; |
| } |