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