]> git.saurik.com Git - apple/xnu.git/blame_incremental - libsyscall/wrappers/stackshot.c
xnu-3247.10.11.tar.gz
[apple/xnu.git] / libsyscall / wrappers / stackshot.c
... / ...
CommitLineData
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;
53 s_config->sc_since_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 */
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
216/*
217 * stackshot_config_dealloc_buffer: dealloc the stackshot buffer and reset the size so that a
218 * stackshot_config_t can be used again
219 *
220 * Inputs: stackshot_config - a pointer to a stackshot_config_t
221 *
222 * Outputs: EINVAL if the passed stackshot_config is NULL or if its buffer is NULL
223 * 0 otherwise
224 */
225int
226stackshot_config_dealloc_buffer(stackshot_config_t *stackshot_config)
227{
228 stackshot_config_t *s_config;
229
230 if (stackshot_config == NULL) {
231 return EINVAL;
232 }
233 s_config = (stackshot_config_t *) stackshot_config;
234
235 if (s_config->sc_size && s_config->sc_buffer) {
236 mach_vm_deallocate(mach_task_self(), (mach_vm_offset_t)s_config->sc_buffer, (mach_vm_size_t)s_config->sc_size);
237 }
238
239 s_config->sc_buffer = 0;
240 s_config->sc_size = 0;
241
242 return 0;
243}
244
245/*
246 * stackshot_config_dealloc: dealloc the stackshot buffer and the stackshot config
247 *
248 * Inputs: stackshot_config - a pointer to a stackshot_config_t
249 *
250 * Outputs: EINVAL if the passed stackshot_cofnig is NULL
251 * 0 otherwise
252 */
253int
254stackshot_config_dealloc(stackshot_config_t *stackshot_config)
255{
256 stackshot_config_t *s_config;
257
258 if (stackshot_config == NULL) {
259 return EINVAL;
260 }
261 s_config = (stackshot_config_t *) stackshot_config;
262
263 if (s_config->sc_size && s_config->sc_buffer) {
264 mach_vm_deallocate(mach_task_self(), (mach_vm_offset_t)s_config->sc_buffer, (mach_vm_size_t)s_config->sc_size);
265 }
266
267 s_config->sc_buffer = 0;
268 s_config->sc_size = 0;
269
270 free(s_config);
271 return 0;
272}