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 "berberis/proxy_loader/proxy_library_builder.h"
18
19 #include <dlfcn.h>
20
21 #include <cstring>
22
23 #include "berberis/base/checks.h"
24 #include "berberis/base/logging.h"
25 #include "berberis/base/tracing.h"
26 #include "berberis/guest_state/guest_state_opaque.h"
27 #include "berberis/runtime_primitives/host_function_wrapper_impl.h"
28
29 namespace berberis {
30
DoBadThunk()31 void DoBadThunk() {
32 LOG_ALWAYS_FATAL("Bad thunk call before %p", __builtin_return_address(0));
33 }
34
DoBadTrampoline(HostCode callee,ThreadState * state)35 void DoBadTrampoline(HostCode callee, ThreadState* state) {
36 CHECK(state);
37 const char* name = static_cast<const char*>(callee);
38 LOG_ALWAYS_FATAL("Bad '%s' call from %p",
39 name ? name : "[unknown name]",
40 ToHostAddr<void>(GetLinkRegister(GetCPUState(*state))));
41 }
42
InterceptSymbol(GuestAddr guest_addr,const char * name)43 void ProxyLibraryBuilder::InterceptSymbol(GuestAddr guest_addr, const char* name) {
44 CHECK(guest_addr);
45
46 // TODO(b/287342829): functions_ are sorted, use binary search!
47 for (size_t i = 0; i < num_functions_; ++i) {
48 const auto& function = functions_[i];
49 if (strcmp(name, function.name) == 0) {
50 void* thunk = function.thunk;
51 if (!thunk) {
52 // Default thunk.
53 thunk = dlsym(handle_, name);
54 }
55 if (!thunk) {
56 // Assume no thunk needed, all work is done by trampoline.
57 thunk = reinterpret_cast<void*>(DoBadThunk);
58 }
59 if (function.marshal_and_call == DoBadTrampoline) {
60 // HACK: DoBadTrampoline needs function name passed as callee!
61 MakeTrampolineCallable(guest_addr, false, DoBadTrampoline, name, name);
62 } else {
63 MakeTrampolineCallable(guest_addr, false, function.marshal_and_call, thunk, name);
64 }
65 return;
66 }
67 }
68
69 // TODO(b/287342829): variables_ are sorted, use binary search!
70 for (size_t i = 0; i < num_variables_; ++i) {
71 const auto& variable = variables_[i];
72 if (strcmp(name, variable.name) == 0) {
73 if (variable.size != sizeof(GuestAddr)) {
74 // TODO(b/287342829): at the moment, all intercepted variables are assumed to be pointers!
75 TRACE("proxy library \"%s\": size mismatch for variable \"%s\"", library_name_, name);
76 }
77 void* addr = dlsym(handle_, name);
78 if (!addr) {
79 TRACE("proxy library \"%s\": symbol for variable \"%s\" is NULL", library_name_, name);
80 } else {
81 // TODO(b/287342829): copy variable.size bytes instead!
82 memcpy(ToHostAddr<void>(guest_addr), addr, sizeof(GuestAddr));
83 }
84 return;
85 }
86 }
87
88 TRACE("proxy library \"%s\": symbol \"%s\" not found", library_name_, name);
89 }
90
Build(const char * library_name,size_t size_translation,const KnownTrampoline * translations,size_t size_data_symbols,const KnownVariable * variables)91 void ProxyLibraryBuilder::Build(const char* library_name,
92 size_t size_translation,
93 const KnownTrampoline* translations,
94 size_t size_data_symbols,
95 const KnownVariable* variables) {
96 handle_ = dlopen(library_name, RTLD_GLOBAL);
97 if (!handle_) {
98 LOG_ALWAYS_FATAL("dlopen failed: %s: %s", library_name, dlerror());
99 }
100
101 library_name_ = library_name;
102 num_functions_ = size_translation;
103 functions_ = translations;
104 num_variables_ = size_data_symbols;
105 variables_ = variables;
106 }
107
108 } // namespace berberis
109