2 * Copyright (c) 2014 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
23 #include <sys/stackshot.h>
24 #include <mach/mach.h>
25 #include <mach/mach_vm.h>
31 * System call entry point
33 int __stack_snapshot_with_config(int stackshot_config_version
, user_addr_t stackshot_config
, size_t stackshot_config_size
);
36 * stackshot_config_create: create and initialize the arguments for a stackshot
38 * Outputs: NULL if malloc fails
39 * a pointer to a new stackshot_config_t on success
42 stackshot_config_create(void)
44 stackshot_config_t
*s_config
;
46 s_config
= malloc(sizeof(stackshot_config_t
));
47 if (s_config
== NULL
) {
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;
61 * stackshot_config_set_pid: set the PID to be traced
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
66 * Outputs: EINVAL if the passed stackshot_config pointer is NULL
70 stackshot_config_set_pid(stackshot_config_t
*stackshot_config
, int pid
)
72 stackshot_config_t
*s_config
;
74 if (stackshot_config
== NULL
) {
78 s_config
= (stackshot_config_t
*) stackshot_config
;
79 s_config
->sc_pid
= pid
;
85 * stackshot_config_set_flags: set the flags to be passed for the stackshot
87 * Inputs: stackshot_config - a pointer to the stackshot_config_t we want to update
88 * flags - flags to pass to stackshot
90 * Outputs: EINVAL if the passed stackshot_config pointer is NULL
94 stackshot_config_set_flags(stackshot_config_t
*stackshot_config
, uint32_t flags
)
96 stackshot_config_t
*s_config
;
98 if (stackshot_config
== NULL
) {
102 s_config
= (stackshot_config_t
*) stackshot_config
;
103 s_config
->sc_flags
= flags
;
109 * stackshot_capture_with_config: take a stackshot with the provided config
111 * Inputs: stackshot_config - a pointer to the stackshot_config_t we want to use
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
129 stackshot_capture_with_config(stackshot_config_t
*stackshot_config
)
132 stackshot_config_t
*s_config
;
134 if (stackshot_config
== NULL
) {
138 s_config
= (stackshot_config_t
*) stackshot_config
;
139 if (s_config
->sc_buffer
!= 0) {
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
));
149 s_config
->sc_buffer
= 0;
150 s_config
->sc_size
= 0;
157 * stackshot_config_get_stackshot_buffer: get a pointer to the buffer containing the stackshot
159 * Inputs: stackshot_config - a pointer to a stackshot_config_t
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
165 stackshot_config_get_stackshot_buffer(stackshot_config_t
*stackshot_config
)
167 stackshot_config_t
*s_config
;
169 if (stackshot_config
== NULL
) {
172 s_config
= (stackshot_config_t
*) stackshot_config
;
174 return ((void *)s_config
->sc_buffer
);
178 * stackshot_config_get_stackshot_size: get the size of the stackshot buffer
180 * Inputs: stackshot_config - a pointer to a stackshot_config_t
182 * Outputs: -1 if the passed stackshot config is NULL or there is no buffer
183 * the length of the stackshot buffer on success
186 stackshot_config_get_stackshot_size(stackshot_config_t
* stackshot_config
)
188 if (stackshot_config
== NULL
|| (void *)stackshot_config
->sc_buffer
== NULL
) {
192 return stackshot_config
->sc_size
;
196 * stackshot_config_set_size_hint: set the size of the stackshot buffer
198 * Inputs: stackshot_config - a pointer to a stackshot_config_t
199 * suggested_size - hint for size allocation of stackshot
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.
205 stackshot_config_set_size_hint(stackshot_config_t
*stackshot_config
, uint32_t suggested_size
)
207 if (stackshot_config
== NULL
|| (void *)stackshot_config
->sc_buffer
!= NULL
) {
211 stackshot_config
->sc_size
= suggested_size
;
217 * stackshot_config_set_delta_timestamp: set the timestamp to use as the basis for the delta stackshot
219 * This timestamp will be used along with STACKSHOT_COLLECT_DELTA_SNAPSHOT flag to collect delta stackshots
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
224 * Outputs: -1 if the passed stackshot config is NULL or there is existing stackshot buffer set.
228 stackshot_config_set_delta_timestamp(stackshot_config_t
*stackshot_config
, uint64_t delta_timestamp
)
230 if (stackshot_config
== NULL
|| (void *)stackshot_config
->sc_buffer
!= NULL
) {
234 stackshot_config
->sc_delta_timestamp
= delta_timestamp
;
241 * stackshot_config_dealloc_buffer: dealloc the stackshot buffer and reset the size so that a
242 * stackshot_config_t can be used again
244 * Inputs: stackshot_config - a pointer to a stackshot_config_t
246 * Outputs: EINVAL if the passed stackshot_config is NULL or if its buffer is NULL
250 stackshot_config_dealloc_buffer(stackshot_config_t
*stackshot_config
)
252 stackshot_config_t
*s_config
;
254 if (stackshot_config
== NULL
) {
257 s_config
= (stackshot_config_t
*) stackshot_config
;
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
);
263 s_config
->sc_buffer
= 0;
264 s_config
->sc_size
= 0;
270 * stackshot_config_dealloc: dealloc the stackshot buffer and the stackshot config
272 * Inputs: stackshot_config - a pointer to a stackshot_config_t
274 * Outputs: EINVAL if the passed stackshot_cofnig is NULL
278 stackshot_config_dealloc(stackshot_config_t
*stackshot_config
)
280 stackshot_config_t
*s_config
;
282 if (stackshot_config
== NULL
) {
285 s_config
= (stackshot_config_t
*) stackshot_config
;
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
);
291 s_config
->sc_buffer
= 0;
292 s_config
->sc_size
= 0;