]>
Commit | Line | Data |
---|---|---|
ada7c492 A |
1 | /* |
2 | * Copyright (c) 2007, 2008, 2009 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
442fbc9d | 5 | * |
ada7c492 A |
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. | |
442fbc9d | 12 | * |
ada7c492 A |
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. | |
442fbc9d | 20 | * |
ada7c492 A |
21 | * @APPLE_LICENSE_HEADER_END@ |
22 | */ | |
23 | ||
24 | #define _XOPEN_SOURCE 600L | |
25 | #include <ucontext.h> | |
26 | #include <errno.h> | |
442fbc9d A |
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 | |
ada7c492 A |
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 | ||
442fbc9d A |
49 | #include <platform/string.h> |
50 | #include <platform/compat.h> | |
51 | ||
ada7c492 A |
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 | ||
442fbc9d | 66 | #if CONFORMANCE_SPECIFIC_HACK |
ada7c492 A |
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; | |
442fbc9d A |
84 | #endif |
85 | ||
86 | uctx->uc_mcontext = mctx; | |
87 | uctx->uc_mcsize = sizeof(*mctx); | |
ada7c492 | 88 | |
442fbc9d | 89 | #if CONFORMANCE_SPECIFIC_HACK |
ada7c492 A |
90 | |
91 | #ifdef __DYNAMIC__ | |
442fbc9d | 92 | uctx->uc_link = (ucontext_t*)(uintptr_t)__in_sigtramp; /* non-zero if in signal handler */ |
ada7c492 | 93 | #else /* !__DYNAMIC__ */ |
442fbc9d | 94 | uctx->uc_link = NULL; |
ada7c492 A |
95 | #endif /* __DYNAMIC__ */ |
96 | ||
442fbc9d | 97 | #endif /* CONFORMANCE_SPECIFIC_HACK */ |
ada7c492 A |
98 | |
99 | sigprocmask(0, NULL, &uctx->uc_sigmask); | |
100 | return mctx; | |
101 | } | |
102 | ||
442fbc9d A |
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 | ||
ada7c492 A |
207 | #else |
208 | ||
209 | int | |
442fbc9d | 210 | getcontext(ucontext_t *uctx) |
ada7c492 A |
211 | { |
212 | errno = ENOTSUP; | |
213 | return -1; | |
214 | } | |
ada7c492 | 215 | #endif |