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 "pthread_translation.h"
18 
19 #include <dlfcn.h>  // dlsym
20 #include <errno.h>
21 #include <unistd.h>  // getpid
22 
23 #include <algorithm>  // std::max
24 #include <vector>
25 
26 #include "berberis/base/logging.h"
27 #include "berberis/base/tracing.h"
28 #include "berberis/guest_abi/function_wrappers.h"
29 #include "berberis/guest_abi/guest_call.h"
30 #include "berberis/guest_abi/guest_params_arch.h"
31 #include "berberis/guest_os_primitives/guest_thread.h"
32 #include "berberis/guest_os_primitives/guest_thread_manager.h"
33 #include "berberis/guest_os_primitives/scoped_pending_signals.h"
34 #include "berberis/guest_state/guest_addr.h"
35 #include "berberis/runtime_primitives/host_stack.h"
36 
37 namespace berberis {
38 
39 namespace {
40 
41 using PthreadCleanupFunc = void (*)(void* arg);
42 
43 }  // namespace
44 
45 // int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
46 //                    void *(*start_routine)(void*), void *arg);
DoCustomTrampoline_pthread_create(HostCode,ProcessState * state)47 void DoCustomTrampoline_pthread_create(HostCode /* callee */,
48                                        ProcessState* state) {
49   auto [thread, guest_attr, func, arg] =
50       GuestParamsValues<decltype(pthread_create)>(state);
51 
52   pthread_attr_t attr;
53   if (guest_attr) {
54     // We'll change the attr, so make a copy.
55     // ATTENTION: this is not standard-compliant, just OK for bionic!
56     memcpy(&attr, guest_attr, sizeof(attr));
57   } else {
58     pthread_attr_init(&attr);
59   }
60 
61   // Avoid using pthread_attr_get/set*, as they do error-checking we don't want
62   // here! ATTENTION: this is not standard-compliant, just OK for bionic!
63   void* guest_stack = attr.stack_base;
64   size_t guest_stack_size = attr.stack_size;
65   size_t guest_guard_size = attr.guard_size;
66   // Ensure host stack is big enough to do translation.
67   // ATTENTION: don't make host stack smaller than guest stack (so don't use the
68   // default size)! Guest might be calling stack hungry host code via
69   // trampolines. Also, this way we don't need to check if guest guard size is
70   // OK for host stack size.
71   attr.stack_base = nullptr;
72   attr.stack_size = std::max(guest_stack_size, GetStackSizeForTranslation());
73 
74   auto&& [ret] = GuestReturnReference<decltype(pthread_create)>(state);
75   ret = CreateNewGuestThread(thread, &attr, guest_stack, guest_stack_size,
76                              guest_guard_size, ToGuestAddr(func),
77                              ToGuestAddr(arg));
78 
79   pthread_attr_destroy(&attr);
80 }
81 
82 // int pthread_join(pthread_t thread, void **retval);
DoCustomTrampoline_pthread_join(HostCode,ProcessState * state)83 void DoCustomTrampoline_pthread_join(HostCode /* callee */,
84                                      ProcessState* state) {
85   auto [guest_thread, retval] =
86       GuestParamsValues<decltype(pthread_join)>(state);
87 
88   ScopedPendingSignalsDisabler scoped_pending_signals_disabler(state->thread);
89   auto&& [ret] = GuestReturnReference<decltype(pthread_join)>(state);
90   ret = pthread_join(guest_thread, retval);
91 }
92 
93 // int pthread_getattr_np(pthread_t thread, pthread_attr_t *attr);
DoCustomTrampoline_pthread_getattr_np(HostCode,ProcessState * state)94 void DoCustomTrampoline_pthread_getattr_np(HostCode /* callee */,
95                                            ProcessState* state) {
96   auto [guest_thread, guest_attr] =
97       GuestParamsValues<decltype(pthread_getattr_np)>(state);
98 
99   // Query host attr.
100   auto&& [ret] = GuestReturnReference<decltype(pthread_getattr_np)>(state);
101   ret = pthread_getattr_np(guest_thread, guest_attr);
102   if (ret != 0) {
103     return;
104   }
105 
106   // Overwrite attr with guest stack values.
107   // ATTENTION: if we fail to find thread in guest threads table, then it means
108   // the thread exists (pthread_getattr_np above succeeded!) but simply doesn't
109   // run any guest code... so don't fail and return attr as reported by host!
110   GuestAddr stack_base;
111   size_t stack_size;
112   size_t guard_size;
113   int error;
114   pid_t tid = pthread_gettid_np(guest_thread);
115   if (GetGuestThreadAttr(tid, &stack_base, &stack_size, &guard_size, &error)) {
116     guest_attr->stack_base = ToHostAddr<void>(stack_base);
117     // TODO(b/78156520): main thread's stack has no guard and its size is
118     // affected by setrlimit(RLIMIT_STACK). At the moment, keep these as
119     // reported by host...
120     if (tid != getpid()) {
121       guest_attr->stack_size = stack_size;
122       guest_attr->guard_size = guard_size;
123     }
124   }
125 }
126 
127 // void __pthread_cleanup_push( __pthread_cleanup_t*      c,
128 //                              __pthread_cleanup_func_t  routine,
129 //                              void*                     arg)
DoCustomTrampoline___pthread_cleanup_push(HostCode,ProcessState * state)130 void DoCustomTrampoline___pthread_cleanup_push(HostCode /* callee */,
131                                                ProcessState* state) {
132   auto [cleanup, routine, arg] =
133       GuestParamsValues<decltype(__pthread_cleanup_push)>(state);
134   __pthread_cleanup_push(
135       cleanup, WrapGuestFunction(routine, "__pthread_cleanup_push-callback"),
136       arg);
137 }
138 
139 // int pthread_key_create(pthread_key_t* key, void (*destructor)(void*));
DoCustomTrampoline_pthread_key_create(HostCode,ProcessState * state)140 void DoCustomTrampoline_pthread_key_create(HostCode /* callee */,
141                                            ProcessState* state) {
142   auto [key, guest_destructor] =
143       GuestParamsValues<decltype(pthread_key_create)>(state);
144   auto&& [ret] = GuestReturnReference<decltype(pthread_key_create)>(state);
145   if (ToGuestAddr(guest_destructor) == 0) {
146     ret = pthread_key_create(key, nullptr);
147   } else {
148     using Destructor = void (*)(void* value);
149     Destructor host_destructor = AsFuncPtr<Destructor>(WrapGuestFunctionImpl(
150         ToGuestAddr(guest_destructor),
151         kGuestFunctionWrapperSignature<Destructor>, RunGuestPthreadKeyDtor,
152         "pthread_key_create-destructor"));
153     ret = pthread_key_create(key, host_destructor);
154   }
155 }
156 
157 // uintptr_t __get_thread_stack_top();
DoCustomTrampoline___get_thread_stack_top(HostCode,ProcessState * state)158 void DoCustomTrampoline___get_thread_stack_top(HostCode /* callee */,
159                                                ProcessState* state) {
160   auto&& [ret] = GuestReturnReference<uintptr_t()>(state);
161   ret = state->thread->GetStackTop();
162 }
163 
164 }  // namespace berberis
165