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