]> git.saurik.com Git - apple/libplatform.git/blame - src/ucontext/generic/getmcontext.c
libplatform-254.40.4.tar.gz
[apple/libplatform.git] / src / ucontext / generic / getmcontext.c
CommitLineData
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__
37extern 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
52extern int __sigaltstack(const stack_t * __restrict, stack_t * __restrict);
53
54#ifdef __DYNAMIC__
55extern int __in_sigtramp;
56#endif /* __DYNAMIC_ */
57
58__attribute__((visibility("hidden")))
59mcontext_t
60getmcontext(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
112extern 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")))
146mcontext_t
147populate_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
209int
442fbc9d 210getcontext(ucontext_t *uctx)
ada7c492
A
211{
212 errno = ENOTSUP;
213 return -1;
214}
ada7c492 215#endif