1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 
17 #include <string.h>  // strcmp
18 
19 #include "EGL/egl.h"
20 #include "EGL/eglext.h"
21 
22 #include "berberis/guest_abi/function_wrappers.h"
23 #include "berberis/guest_abi/guest_arguments.h"
24 #include "berberis/guest_abi/guest_params.h"
25 #include "berberis/guest_state/guest_state.h"
26 #include "berberis/proxy_loader/proxy_library_builder.h"
27 #include "berberis/runtime_primitives/known_guest_function_wrapper.h"
28 #include "berberis/runtime_primitives/runtime_library.h"
29 #include "berberis/base/tracing.h"
30 #include "native_bridge_proxy/android_api/libEGL/gl_common_defs.h"
31 
32 namespace berberis {
33 
34 namespace {
35 
36 // glDebugMessageCallback
37 // glDebugMessageCallbackARB
38 // glDebugMessageCallbackKHR
DoCustomTrampolineWithThunk_glDebugMessageCallback(HostCode callee,ProcessState * state)39 void DoCustomTrampolineWithThunk_glDebugMessageCallback(HostCode callee, ProcessState* state) {
40   // Prototypes are not defined in EGL headers - even though library itself is supposed to know
41   // about these functions.
42   using Callback = void (*)(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, void*, void*);
43   using PFN_callee = void (*)(Callback, void* Param);
44   PFN_callee callee_function = AsFuncPtr(callee);
45 
46   auto [guest_callback, param] = GuestParamsValues<PFN_callee>(state);
47 
48   Callback host_callback = WrapGuestFunction(guest_callback, "glDebugMessageCallback-callback");
49 
50   callee_function(host_callback, param);
51 }
52 const auto DoCustomTrampolineWithThunk_glDebugMessageCallbackARB =
53     DoCustomTrampolineWithThunk_glDebugMessageCallback;
54 const auto DoCustomTrampolineWithThunk_glDebugMessageCallbackKHR =
55     DoCustomTrampolineWithThunk_glDebugMessageCallback;
56 
RunGuest_glDebugMessageCallback(GuestAddr pc,GuestArgumentBuffer * buf)57 void RunGuest_glDebugMessageCallback(GuestAddr pc, GuestArgumentBuffer* buf) {
58   // Prototypes are not defined in EGL headers - even though library itself is supposed to know
59   // about these functions.
60   using Callback = void (*)(uint32_t, uint32_t, uint32_t, uint32_t, uint32_t, void*, void*);
61   using PFN_callee = void (*)(Callback, void* Param);
62 
63   auto [callback, user_param] = HostArgumentsValues<PFN_callee>(buf);
64 
65   WrapHostFunction(callback, "glDebugMessageCallback_DEBUGPROC");
66   RunGuestCall(pc, buf);
67 }
68 
69 const auto RunGuest_glDebugMessageCallbackARB = RunGuest_glDebugMessageCallback;
70 const auto RunGuest_glDebugMessageCallbackKHR = RunGuest_glDebugMessageCallback;
71 
RunGuest_glGetPointerv(GuestAddr pc,GuestArgumentBuffer * buf)72 void RunGuest_glGetPointerv(GuestAddr pc, GuestArgumentBuffer* buf) {
73   // Note: we don't need to do any tricks here yet since when Host function is converted to guest
74   // function it's actuall address doesn't change.
75   RunGuestCall(pc, buf);
76 }
77 
78 const auto RunGuest_glGetPointervEXT = RunGuest_glGetPointerv;
79 const auto RunGuest_glGetPointervKHR = RunGuest_glGetPointerv;
80 
81 // glGetPointerv
82 // glGetPointervEXT
83 // glGetPointervKHR
DoCustomTrampolineWithThunk_glGetPointerv(HostCode callee,ProcessState * state)84 void DoCustomTrampolineWithThunk_glGetPointerv(HostCode callee, ProcessState* state) {
85   // Prototypes are not defined in EGL headers - even though library itself is supposed to know
86   // about these functions.
87   using PFN_callee = void (*)(uint32_t pname, void** params);
88   PFN_callee callee_function = AsFuncPtr(callee);
89 
90   auto [pname, value] = GuestParamsValues<PFN_callee>(state);
91 
92   callee_function(pname, value);
93 
94   // This maybe any version of GLES, so compare to all possible key values in different versions.
95   if (pname == EGL_DEBUG_CALLBACK_KHR || pname == GLES2_AND_GLES3_DEBUG_CALLBACK_FUNCTION_KHR) {
96     // If callback is registered by guest, return the original guest address,
97     // since guest code may expect that (b/71363904).
98     GuestAddr guest_addr = SlowFindGuestAddrByWrapperAddr(*value);
99     if (guest_addr) {
100       *value = reinterpret_cast<void*>(guest_addr);
101     }
102   }
103 }
104 const auto DoCustomTrampolineWithThunk_glGetPointervEXT = DoCustomTrampolineWithThunk_glGetPointerv;
105 const auto DoCustomTrampolineWithThunk_glGetPointervKHR = DoCustomTrampolineWithThunk_glGetPointerv;
106 
107 // Forward decl for android_api/egl/opengl_trampolines-inl.h:kOpenGLTrampolines.
108 void DoCustomTrampolineWithThunk_eglGetProcAddress(HostCode callee, ProcessState* state);
109 void RunGuest_eglGetProcAddress(GuestAddr pc, GuestArgumentBuffer* buf);
110 
111 #include "opengl_trampolines-inl.h"  // generated file NOLINT [build/include]
112 
WrapEglHostFunction(const char * name,HostCode function)113 bool WrapEglHostFunction(const char* name, HostCode function) {
114   if (name == nullptr || function == nullptr) {
115     return false;
116   }
117 
118   // TODO(eaeltsin): kOpenGLTrampolines are sorted, might use binary search!
119   for (const auto& t : kOpenGLTrampolines) {
120     if (strcmp(name, t.name) == 0) {
121       if (!t.marshal_and_call) {
122         break;
123       }
124 
125       WrapHostFunctionImpl(function, t.marshal_and_call, name);
126       return true;
127     }
128   }
129 
130   return false;
131 }
132 
WrapEglGuestFunction(const char * name,GuestAddr function)133 HostCode WrapEglGuestFunction(const char* name, GuestAddr function) {
134   if (name == nullptr || function == kNullGuestAddr) {
135     return nullptr;
136   }
137 
138   // TODO(eaeltsin): kOpenGLTrampolines are sorted, might use binary search!
139   for (const auto& t : kOpenGLTrampolines) {
140     if (strcmp(name, t.name) == 0) {
141       if (!t.wrapper) {
142         break;
143       }
144 
145       return t.wrapper(function);
146     }
147   }
148 
149   return nullptr;
150 }
151 
152 // void (*eglGetProcAddress(char const* procname))();
DoCustomTrampolineWithThunk_eglGetProcAddress(HostCode callee,ProcessState * state)153 void DoCustomTrampolineWithThunk_eglGetProcAddress(HostCode callee, ProcessState* state) {
154   using PFN_callee = decltype(&eglGetProcAddress);
155   PFN_callee callee_function = AsFuncPtr(callee);
156   auto [proc_name] = GuestParamsValues<PFN_callee>(state);
157 
158   auto&& [ret] = GuestReturnReference<PFN_callee>(state);
159   ret = callee_function(proc_name);
160   if (!ToGuestAddr(ret)) {
161     return;
162   }
163 
164   if (!WrapEglHostFunction(proc_name, ToHostCode(ret))) {
165     // Host proc exists but we failed to wrap it.  That's not fatal error because application
166     // may have a fallback code if certain GLES4-5-6 function is not available in our translator
167     // but is provided by drivers... but we want to know about it from logs anyway.
168     ALOGE("eglGetProcAddress(\"%s\") failed", static_cast<const char*>(proc_name));
169     TRACE("eglGetProcAddress(\"%s\") failed", static_cast<const char*>(proc_name));
170     ret = 0;
171     return;
172   }
173 }
174 
RunGuest_eglGetProcAddress(GuestAddr pc,GuestArgumentBuffer * buf)175 void RunGuest_eglGetProcAddress(GuestAddr pc, GuestArgumentBuffer* buf) {
176   auto [proc_name] = HostArgumentsValues<decltype(eglGetProcAddress)>(buf);
177   RunGuestCall(pc, buf);
178   auto&& [result] = HostResultReference<decltype(eglGetProcAddress)>(buf);
179   if (!WrapEglHostFunction(proc_name, ToHostCode(GuestType(result)))) {
180     result = nullptr;
181   }
182 }
183 
184 #if defined(NATIVE_BRIDGE_GUEST_ARCH_ARM) && defined(__i386__)
185 
186 #include "trampolines_arm_to_x86-inl.h"  // generated file NOLINT [build/include]
187 
188 #elif defined(NATIVE_BRIDGE_GUEST_ARCH_ARM64) && defined(__x86_64__)
189 
190 #include "trampolines_arm64_to_x86_64-inl.h"  // generated file NOLINT [build/include]
191 
192 #elif defined(NATIVE_BRIDGE_GUEST_ARCH_RISCV64) && defined(__x86_64__)
193 
194 #include "trampolines_riscv64_to_x86_64-inl.h"  // generated file NOLINT [build/include]
195 
196 #else
197 
198 #error "Unknown guest/host arch combination"
199 
200 #endif
201 
202 using PFNEGLGETNEXTLAYERPROCADDRESSPROC = void* (*)(void*, const char*);
203 
204 using EGLFuncPointer = __eglMustCastToProperFunctionPointerType;
205 
206 using AndroidGLESLayer_InitializePtr =
207     EGLAPI void (*)(void* layer_id, PFNEGLGETNEXTLAYERPROCADDRESSPROC get_next_layer_proc_address);
208 using AndroidGLESLayer_GetProcAddressPtr = EGLAPI void* (*)(const char* funcName,
209                                                             EGLFuncPointer next);
210 
DoCustomTrampolineWithThunk_eglNextLayerProcAddressProc(HostCode callee,ProcessState * state)211 void DoCustomTrampolineWithThunk_eglNextLayerProcAddressProc(HostCode callee, ProcessState* state) {
212   auto [layer_id, proc_name] = GuestParamsValues<PFNEGLGETNEXTLAYERPROCADDRESSPROC>(state);
213   PFNEGLGETNEXTLAYERPROCADDRESSPROC get_next_layer_proc_address = AsFuncPtr(callee);
214 
215   auto&& [ret] = GuestReturnReference<PFNEGLGETNEXTLAYERPROCADDRESSPROC>(state);
216   ret = get_next_layer_proc_address(layer_id, proc_name);
217   if (!ret) {
218     return;
219   }
220 
221   if (!WrapEglHostFunction(proc_name, ret)) {
222     // Host proc exists but we failed to wrap it.
223     // Host proc exists but we failed to wrap it.  That's not fatal error because application
224     // may have a fallback code if certain GLES4-5-6 function is not available in our translator
225     // but is provided by drivers... but we want to know about it from logs anyway.
226     ALOGE("eglGetProcAddress(\"%s\") failed", static_cast<const char*>(proc_name));
227     TRACE("eglGetProcAddress(\"%s\") failed", static_cast<const char*>(proc_name));
228     ret = 0;
229     return;
230   }
231 }
232 
RunGuestAndroidGLESLayer_Initialize(GuestAddr pc,GuestArgumentBuffer * buf)233 void RunGuestAndroidGLESLayer_Initialize(GuestAddr pc, GuestArgumentBuffer* buf) {
234   auto [layer_id, get_next_layer_proc_address] =
235       HostArgumentsValues<AndroidGLESLayer_InitializePtr>(buf);
236   WrapHostFunctionImpl(reinterpret_cast<void*>(get_next_layer_proc_address),
237                        DoCustomTrampolineWithThunk_eglNextLayerProcAddressProc,
238                        "RunGuestAndroidGLESLayer_Initialize");
239   RunGuestCall(pc, buf);
240 }
241 
242 
RunGuestAndroidGLESLayer_GetProcAddress(GuestAddr pc,GuestArgumentBuffer * buf)243 void RunGuestAndroidGLESLayer_GetProcAddress(GuestAddr pc, GuestArgumentBuffer* buf) {
244   auto [proc_name, get_next_layer_proc_address] =
245       HostArgumentsValues<AndroidGLESLayer_GetProcAddressPtr>(buf);
246   auto&& [host_result] = HostResultReference<AndroidGLESLayer_GetProcAddressPtr>(buf);
247   if (get_next_layer_proc_address != nullptr &&
248       !WrapEglHostFunction(proc_name, ToHostCode(GuestType(get_next_layer_proc_address)))) {
249     host_result = const_cast<void*>(ToHostCode(GuestType(get_next_layer_proc_address)));
250     return;
251   }
252   RunGuestCall(pc, buf);
253   auto [guest_result] = GuestResultValue<AndroidGLESLayer_GetProcAddressPtr>(buf);
254   host_result = const_cast<void*>(WrapEglGuestFunction(proc_name, ToGuestAddr(guest_result)));
255 }
256 
InitProxyLibrary(ProxyLibraryBuilder * builder)257 extern "C" void InitProxyLibrary(ProxyLibraryBuilder* builder) {
258   builder->Build("libEGL.so",
259                  sizeof(kKnownTrampolines) / sizeof(kKnownTrampolines[0]),
260                  kKnownTrampolines,
261                  sizeof(kKnownVariables) / sizeof(kKnownVariables[0]),
262                  kKnownVariables);
263   RegisterKnownGuestFunctionWrapper("AndroidGLESLayer_Initialize", [](GuestAddr pc) {
264     return WrapGuestFunctionImpl(pc,
265                                  kGuestFunctionWrapperSignature<AndroidGLESLayer_InitializePtr>,
266                                  RunGuestAndroidGLESLayer_Initialize,
267                                  "AndroidGLESLayer_Initialize");
268   });
269   RegisterKnownGuestFunctionWrapper("AndroidGLESLayer_GetProcAddress", [](GuestAddr pc) {
270     return WrapGuestFunctionImpl(pc,
271                                  kGuestFunctionWrapperSignature<AndroidGLESLayer_GetProcAddressPtr>,
272                                  RunGuestAndroidGLESLayer_GetProcAddress,
273                                  "AndroidGLESLayer_GetProcAddress");
274   });
275 }
276 
277 }  // namespace
278 
279 }  // namespace berberis
280