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