]> git.saurik.com Git - apple/xnu.git/blame - libsyscall/wrappers/stackshot.c
xnu-3789.41.3.tar.gz
[apple/xnu.git] / libsyscall / wrappers / stackshot.c
CommitLineData
3e170ce0
A
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 */
33int __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 */
41stackshot_config_t *
42stackshot_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;
39037602 53 s_config->sc_delta_timestamp = 0;
3e170ce0
A
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 */
69int
70stackshot_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 */
93int
94stackshot_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 */
128int
129stackshot_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 = &s_config->sc_buffer;
144 s_config->sc_out_size_addr = &s_config->sc_size;
145 ret = __stack_snapshot_with_config(STACKSHOT_CONFIG_TYPE, 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 */
164void *
165stackshot_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 */
185uint32_t
186stackshot_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 */
204int
205stackshot_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
39037602
A
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 */
227int
228stackshot_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
3e170ce0
A
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 */
249int
250stackshot_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 */
277int
278stackshot_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}