]> git.saurik.com Git - apple/xnu.git/blob - libsyscall/wrappers/stackshot.c
xnu-4903.221.2.tar.gz
[apple/xnu.git] / libsyscall / wrappers / stackshot.c
1 /*
2 * Copyright (c) 2014 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 #include <sys/stackshot.h>
24 #include <mach/mach.h>
25 #include <mach/mach_vm.h>
26 #include <stdint.h>
27 #include <stdlib.h>
28 #include <errno.h>
29
30 /*
31 * System call entry point
32 */
33 int __stack_snapshot_with_config(int stackshot_config_version, user_addr_t stackshot_config, size_t stackshot_config_size);
34
35 /*
36 * stackshot_config_create: create and initialize the arguments for a stackshot
37 *
38 * Outputs: NULL if malloc fails
39 * a pointer to a new stackshot_config_t on success
40 */
41 stackshot_config_t *
42 stackshot_config_create(void)
43 {
44 stackshot_config_t *s_config;
45
46 s_config = malloc(sizeof(stackshot_config_t));
47 if (s_config == NULL) {
48 return NULL;
49 }
50
51 s_config->sc_pid = -1;
52 s_config->sc_flags = 0;
53 s_config->sc_delta_timestamp = 0;
54 s_config->sc_buffer = 0;
55 s_config->sc_size = 0;
56
57 return s_config;
58 }
59
60 /*
61 * stackshot_config_set_pid: set the PID to be traced
62 *
63 * Inputs: stackshot_config - a pointer to the stackshot_config_t we want to update
64 * pid - process id of process to be traced, or -1 for the entire system
65 *
66 * Outputs: EINVAL if the passed stackshot_config pointer is NULL
67 * 0 on success
68 */
69 int
70 stackshot_config_set_pid(stackshot_config_t *stackshot_config, int pid)
71 {
72 stackshot_config_t *s_config;
73
74 if (stackshot_config == NULL) {
75 return EINVAL;
76 }
77
78 s_config = (stackshot_config_t *) stackshot_config;
79 s_config->sc_pid = pid;
80
81 return 0;
82 }
83
84 /*
85 * stackshot_config_set_flags: set the flags to be passed for the stackshot
86 *
87 * Inputs: stackshot_config - a pointer to the stackshot_config_t we want to update
88 * flags - flags to pass to stackshot
89 *
90 * Outputs: EINVAL if the passed stackshot_config pointer is NULL
91 * 0 on success
92 */
93 int
94 stackshot_config_set_flags(stackshot_config_t *stackshot_config, uint32_t flags)
95 {
96 stackshot_config_t *s_config;
97
98 if (stackshot_config == NULL) {
99 return EINVAL;
100 }
101
102 s_config = (stackshot_config_t *) stackshot_config;
103 s_config->sc_flags = flags;
104
105 return 0;
106 }
107
108 /*
109 * stackshot_capture_with_config: take a stackshot with the provided config
110 *
111 * Inputs: stackshot_config - a pointer to the stackshot_config_t we want to use
112 *
113 * Outputs: EINVAL if the passed stackshot_config pointer is NULL, a caller is trying
114 * to reuse a config without deallocating its buffer or if there is a
115 * problem with the arguments
116 * EFAULT if there was a problem with accessing the arguments from the kernel
117 * EPERM if the caller is not privileged
118 * ENOTSUP if the caller is passing a stackshot config version that is not
119 * supported by the kernel (indicates libsyscall:kernel mismatch),
120 * or if the caller is requesting unsupported flags
121 * ENOMEM if the kernel is unable to allocate memory
122 * ENOSPC if the caller doesn't have enough space in their address space for
123 * the kernel to remap the buffer
124 * ENOENT if the caller is requesting an existing buffer that doesn't exist
125 * or the target PID isn't found
126 * 0 on success
127 */
128 int
129 stackshot_capture_with_config(stackshot_config_t *stackshot_config)
130 {
131 int ret;
132 stackshot_config_t *s_config;
133
134 if (stackshot_config == NULL) {
135 return EINVAL;
136 }
137
138 s_config = (stackshot_config_t *) stackshot_config;
139 if (s_config->sc_buffer != 0) {
140 return EINVAL;
141 }
142
143 s_config->sc_out_buffer_addr = (uintptr_t)&s_config->sc_buffer;
144 s_config->sc_out_size_addr = (uintptr_t)&s_config->sc_size;
145 ret = __stack_snapshot_with_config(STACKSHOT_CONFIG_TYPE, (uintptr_t)s_config, sizeof(stackshot_config_t));
146
147 if (ret != 0) {
148 ret = errno;
149 s_config->sc_buffer = 0;
150 s_config->sc_size = 0;
151 }
152
153 return ret;
154 }
155
156 /*
157 * stackshot_config_get_stackshot_buffer: get a pointer to the buffer containing the stackshot
158 *
159 * Inputs: stackshot_config - a pointer to a stackshot_config_t
160 *
161 * Outputs: NULL if the passed stackshot_config is NULL or if its buffer is NULL
162 * a pointer to the buffer containing the stackshot on success
163 */
164 void *
165 stackshot_config_get_stackshot_buffer(stackshot_config_t *stackshot_config)
166 {
167 stackshot_config_t *s_config;
168
169 if (stackshot_config == NULL) {
170 return NULL;
171 }
172 s_config = (stackshot_config_t *) stackshot_config;
173
174 return ((void *)s_config->sc_buffer);
175 }
176
177 /*
178 * stackshot_config_get_stackshot_size: get the size of the stackshot buffer
179 *
180 * Inputs: stackshot_config - a pointer to a stackshot_config_t
181 *
182 * Outputs: -1 if the passed stackshot config is NULL or there is no buffer
183 * the length of the stackshot buffer on success
184 */
185 uint32_t
186 stackshot_config_get_stackshot_size(stackshot_config_t * stackshot_config)
187 {
188 if (stackshot_config == NULL || (void *)stackshot_config->sc_buffer == NULL) {
189 return -1;
190 }
191
192 return stackshot_config->sc_size;
193 }
194
195 /*
196 * stackshot_config_set_size_hint: set the size of the stackshot buffer
197 *
198 * Inputs: stackshot_config - a pointer to a stackshot_config_t
199 * suggested_size - hint for size allocation of stackshot
200 *
201 * Outputs: -1 if the passed stackshot config is NULL or there is existing stackshot buffer set.
202 * the length of the stackshot buffer on success.
203 */
204 int
205 stackshot_config_set_size_hint(stackshot_config_t *stackshot_config, uint32_t suggested_size)
206 {
207 if (stackshot_config == NULL || (void *)stackshot_config->sc_buffer != NULL) {
208 return -1;
209 }
210
211 stackshot_config->sc_size = suggested_size;
212
213 return 0;
214 }
215
216 /*
217 * stackshot_config_set_delta_timestamp: set the timestamp to use as the basis for the delta stackshot
218 *
219 * This timestamp will be used along with STACKSHOT_COLLECT_DELTA_SNAPSHOT flag to collect delta stackshots
220 *
221 * Inputs: stackshot_config - a pointer to a stackshot_config_t
222 * delta_timestamp - timestamp in MachAbsoluteTime units to be used as the basis for a delta stackshot
223 *
224 * Outputs: -1 if the passed stackshot config is NULL or there is existing stackshot buffer set.
225 * 0 on success
226 */
227 int
228 stackshot_config_set_delta_timestamp(stackshot_config_t *stackshot_config, uint64_t delta_timestamp)
229 {
230 if (stackshot_config == NULL || (void *)stackshot_config->sc_buffer != NULL) {
231 return -1;
232 }
233
234 stackshot_config->sc_delta_timestamp = delta_timestamp;
235
236 return 0;
237 }
238
239
240 /*
241 * stackshot_config_dealloc_buffer: dealloc the stackshot buffer and reset the size so that a
242 * stackshot_config_t can be used again
243 *
244 * Inputs: stackshot_config - a pointer to a stackshot_config_t
245 *
246 * Outputs: EINVAL if the passed stackshot_config is NULL or if its buffer is NULL
247 * 0 otherwise
248 */
249 int
250 stackshot_config_dealloc_buffer(stackshot_config_t *stackshot_config)
251 {
252 stackshot_config_t *s_config;
253
254 if (stackshot_config == NULL) {
255 return EINVAL;
256 }
257 s_config = (stackshot_config_t *) stackshot_config;
258
259 if (s_config->sc_size && s_config->sc_buffer) {
260 mach_vm_deallocate(mach_task_self(), (mach_vm_offset_t)s_config->sc_buffer, (mach_vm_size_t)s_config->sc_size);
261 }
262
263 s_config->sc_buffer = 0;
264 s_config->sc_size = 0;
265
266 return 0;
267 }
268
269 /*
270 * stackshot_config_dealloc: dealloc the stackshot buffer and the stackshot config
271 *
272 * Inputs: stackshot_config - a pointer to a stackshot_config_t
273 *
274 * Outputs: EINVAL if the passed stackshot_cofnig is NULL
275 * 0 otherwise
276 */
277 int
278 stackshot_config_dealloc(stackshot_config_t *stackshot_config)
279 {
280 stackshot_config_t *s_config;
281
282 if (stackshot_config == NULL) {
283 return EINVAL;
284 }
285 s_config = (stackshot_config_t *) stackshot_config;
286
287 if (s_config->sc_size && s_config->sc_buffer) {
288 mach_vm_deallocate(mach_task_self(), (mach_vm_offset_t)s_config->sc_buffer, (mach_vm_size_t)s_config->sc_size);
289 }
290
291 s_config->sc_buffer = 0;
292 s_config->sc_size = 0;
293
294 free(s_config);
295 return 0;
296 }