]> git.saurik.com Git - apple/libplatform.git/blob - src/ucontext/generic/getmcontext.c
libplatform-254.40.4.tar.gz
[apple/libplatform.git] / src / ucontext / generic / getmcontext.c
1 /*
2 * Copyright (c) 2007, 2008, 2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #define _XOPEN_SOURCE 600L
25 #include <ucontext.h>
26 #include <errno.h>
27 #include <stdlib.h>
28 #include <stdbool.h>
29 #include <TargetConditionals.h>
30
31 /* This is a macro to capture all the code added in here that is purely to make
32 * conformance tests pass and seems to have no functional reason nor is it
33 * required by the standard */
34 #define CONFORMANCE_SPECIFIC_HACK 1
35
36 #ifdef __DYNAMIC__
37 extern int __in_sigtramp;
38 #endif /* __DYNAMIC_ */
39
40 #if TARGET_OS_OSX || TARGET_OS_DRIVERKIT
41
42 #if defined(__x86_64__) || defined(__i386__)
43
44 #include <sys/resource.h>
45 #include <stddef.h>
46 #include <stdint.h>
47 #include <signal.h>
48
49 #include <platform/string.h>
50 #include <platform/compat.h>
51
52 extern int __sigaltstack(const stack_t * __restrict, stack_t * __restrict);
53
54 #ifdef __DYNAMIC__
55 extern int __in_sigtramp;
56 #endif /* __DYNAMIC_ */
57
58 __attribute__((visibility("hidden")))
59 mcontext_t
60 getmcontext(ucontext_t *uctx, void *sp)
61 {
62 mcontext_t mctx = (mcontext_t)&uctx->__mcontext_data;
63 size_t stacksize = 0;
64 stack_t stack;
65
66 #if CONFORMANCE_SPECIFIC_HACK
67 uctx->uc_stack.ss_sp = sp;
68 uctx->uc_stack.ss_flags = 0;
69
70 if (0 == __sigaltstack(NULL, &stack)) {
71 if (stack.ss_flags & SS_ONSTACK) {
72 uctx->uc_stack = stack;
73 stacksize = stack.ss_size;
74 }
75 }
76
77 if (stacksize == 0) {
78 struct rlimit rlim;
79 if (0 == getrlimit(RLIMIT_STACK, &rlim))
80 stacksize = rlim.rlim_cur;
81 }
82
83 uctx->uc_stack.ss_size = stacksize;
84 #endif
85
86 uctx->uc_mcontext = mctx;
87 uctx->uc_mcsize = sizeof(*mctx);
88
89 #if CONFORMANCE_SPECIFIC_HACK
90
91 #ifdef __DYNAMIC__
92 uctx->uc_link = (ucontext_t*)(uintptr_t)__in_sigtramp; /* non-zero if in signal handler */
93 #else /* !__DYNAMIC__ */
94 uctx->uc_link = NULL;
95 #endif /* __DYNAMIC__ */
96
97 #endif /* CONFORMANCE_SPECIFIC_HACK */
98
99 sigprocmask(0, NULL, &uctx->uc_sigmask);
100 return mctx;
101 }
102
103 #elif defined(__arm64__)
104
105 #include <signal.h>
106 #include <strings.h>
107 #include <stdint.h>
108
109 #include <platform/string.h>
110 #include <platform/compat.h>
111
112 extern int __sigaltstack(const stack_t * __restrict, stack_t * __restrict);
113
114 /* @function populate_signal_stack_context
115 *
116 * @note
117 *
118 * _STRUCT_UCONTEXT {
119 * int uc_onstack;
120 * __darwin_sigset_t uc_sigmask; // signal mask used by this context
121 * _STRUCT_SIGALTSTACK uc_stack; // stack used by this context
122 * _STRUCT_UCONTEXT *uc_link; // pointer to resuming context
123 * __darwin_size_t uc_mcsize; // size of the machine context passed in
124 * _STRUCT_MCONTEXT *uc_mcontext; // pointer to machine specific context
125 * #ifdef _XOPEN_SOURCE
126 * _STRUCT_MCONTEXT __mcontext_data;
127 * #endif
128 * };
129 *
130 * populate_signal_stack_context unconditionally populates the following fields:
131 * uc_sigmask
132 * uc_mcontext
133 * uc_mcsize
134 * __mcontext_data
135 * uc_link
136 *
137 * The standard specifies this about uc_stack:
138 *
139 * Before a call is made to makecontext(), the application shall ensure
140 * that the context being modified has a stack allocated for it.
141 *
142 * ie. the client is generally responsible for managing the stack on on which
143 * their context runs and initializing it properly.
144 */
145 __attribute__((visibility("hidden")))
146 mcontext_t
147 populate_signal_stack_context(ucontext_t *ucp, void *sp)
148 {
149 #if CONFORMANCE_SPECIFIC_HACK
150 /* The conformance tests seems to require that we populate the uc_stack in
151 * getcontext even though the standard requires - as stated above - that the
152 * clients manage the stack that their code runs on. This makes no
153 * functional sense but is put in here to make conformance tests work */
154 stack_t stack;
155
156 if (0 == __sigaltstack(NULL, &stack) && (stack.ss_flags & SA_ONSTACK)) {
157 } else {
158 stack.ss_sp = sp;
159
160 // This stacksize is the wrong number - it provides the stack size of
161 // the main thread and not the current thread. We can't know the
162 // stacksize of the current thread without jumping through some crazy
163 // hoops and it seems like per the standard, this field should not be
164 // required anyways since the client should be allocating and managing
165 // stacks themselves for makecontext.
166 struct rlimit rlim;
167 if (0 == getrlimit(RLIMIT_STACK, &rlim))
168 stack.ss_size = rlim.rlim_cur;
169 }
170 ucp->uc_stack = stack;
171 #endif
172
173 /* Populate signal information */
174 sigprocmask(SIG_UNBLOCK, NULL, &ucp->uc_sigmask);
175
176 /* Always use the mcontext that is embedded in the struct */
177 mcontext_t mctx = (mcontext_t) &ucp->__mcontext_data;
178 ucp->uc_mcontext = mctx;
179 ucp->uc_mcsize = sizeof(*mctx);
180
181 #if CONFORMANCE_SPECIFIC_HACK
182 /* The conformance tests for getcontext requires that:
183 * uc_link = 0 if we're in the "main context"
184 * uc_link = non-0 if we're on signal context while calling getcontext
185 *
186 * It seems like it doesn't require uc_link to a valid pointer in the 2nd
187 * case, just not 0. It also seems to require that the uc_link is
188 * diversified if we have multiple contexts populated from the signal stack.
189 * So we have it be the address of the in_signal_handler value.
190 *
191 * AFAICT, there seems to be no reason to require populating uc_link at all
192 * but it is what the tests expects.
193 */
194 #ifdef __DYNAMIC__
195 ucp->uc_link = (ucontext_t*)(uintptr_t)__in_sigtramp; /* non-zero if in signal handler */
196 #else /* !__DYNAMIC__ */
197 ucp->uc_link = NULL;
198 #endif /* __DYNAMIC__ */
199
200 #endif
201
202 return mctx;
203 }
204
205 #endif /* arm64 || x86_64 || i386 */
206
207 #else
208
209 int
210 getcontext(ucontext_t *uctx)
211 {
212 errno = ENOTSUP;
213 return -1;
214 }
215 #endif