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;
56 s_config
->sc_pagetable_mask
= 0;
62 * stackshot_config_set_pid: set the PID to be traced
64 * Inputs: stackshot_config - a pointer to the stackshot_config_t we want to update
65 * pid - process id of process to be traced, or -1 for the entire system
67 * Outputs: EINVAL if the passed stackshot_config pointer is NULL
71 stackshot_config_set_pid(stackshot_config_t
*stackshot_config
, int pid
)
73 stackshot_config_t
*s_config
;
75 if (stackshot_config
== NULL
) {
79 s_config
= (stackshot_config_t
*) stackshot_config
;
80 s_config
->sc_pid
= pid
;
86 * stackshot_config_set_flags: set the flags to be passed for the stackshot
88 * Inputs: stackshot_config - a pointer to the stackshot_config_t we want to update
89 * flags - flags to pass to stackshot
91 * Outputs: EINVAL if the passed stackshot_config pointer is NULL
95 stackshot_config_set_flags(stackshot_config_t
*stackshot_config
, uint64_t flags
)
97 stackshot_config_t
*s_config
;
99 if (stackshot_config
== NULL
) {
103 s_config
= (stackshot_config_t
*) stackshot_config
;
104 s_config
->sc_flags
= flags
;
110 * stackshot_capture_with_config: take a stackshot with the provided config
112 * Inputs: stackshot_config - a pointer to the stackshot_config_t we want to use
114 * Outputs: EINVAL if the passed stackshot_config pointer is NULL, a caller is trying
115 * to reuse a config without deallocating its buffer or if there is a
116 * problem with the arguments
117 * EFAULT if there was a problem with accessing the arguments from the kernel
118 * EPERM if the caller is not privileged
119 * ENOTSUP if the caller is passing a stackshot config version that is not
120 * supported by the kernel (indicates libsyscall:kernel mismatch),
121 * or if the caller is requesting unsupported flags
122 * ENOMEM if the kernel is unable to allocate memory
123 * ENOSPC if the caller doesn't have enough space in their address space for
124 * the kernel to remap the buffer
125 * ENOENT if the caller is requesting an existing buffer that doesn't exist
126 * or the target PID isn't found
130 stackshot_capture_with_config(stackshot_config_t
*stackshot_config
)
133 stackshot_config_t
*s_config
;
135 if (stackshot_config
== NULL
) {
139 s_config
= (stackshot_config_t
*) stackshot_config
;
140 if (s_config
->sc_buffer
!= 0) {
144 s_config
->sc_out_buffer_addr
= (uintptr_t)&s_config
->sc_buffer
;
145 s_config
->sc_out_size_addr
= (uintptr_t)&s_config
->sc_size
;
146 ret
= __stack_snapshot_with_config(STACKSHOT_CONFIG_TYPE
, (uintptr_t)s_config
, sizeof(stackshot_config_t
));
150 s_config
->sc_buffer
= 0;
151 s_config
->sc_size
= 0;
158 * stackshot_config_get_stackshot_buffer: get a pointer to the buffer containing the stackshot
160 * Inputs: stackshot_config - a pointer to a stackshot_config_t
162 * Outputs: NULL if the passed stackshot_config is NULL or if its buffer is NULL
163 * a pointer to the buffer containing the stackshot on success
166 stackshot_config_get_stackshot_buffer(stackshot_config_t
*stackshot_config
)
168 stackshot_config_t
*s_config
;
170 if (stackshot_config
== NULL
) {
173 s_config
= (stackshot_config_t
*) stackshot_config
;
175 return (void *)s_config
->sc_buffer
;
179 * stackshot_config_get_stackshot_size: get the size of the stackshot buffer
181 * Inputs: stackshot_config - a pointer to a stackshot_config_t
183 * Outputs: -1 if the passed stackshot config is NULL or there is no buffer
184 * the length of the stackshot buffer on success
187 stackshot_config_get_stackshot_size(stackshot_config_t
* stackshot_config
)
189 if (stackshot_config
== NULL
|| (void *)stackshot_config
->sc_buffer
== NULL
) {
193 return stackshot_config
->sc_size
;
197 * stackshot_config_set_size_hint: set the size of the stackshot buffer
199 * Inputs: stackshot_config - a pointer to a stackshot_config_t
200 * suggested_size - hint for size allocation of stackshot
202 * Outputs: -1 if the passed stackshot config is NULL or there is existing stackshot buffer set.
203 * the length of the stackshot buffer on success.
206 stackshot_config_set_size_hint(stackshot_config_t
*stackshot_config
, uint32_t suggested_size
)
208 if (stackshot_config
== NULL
|| (void *)stackshot_config
->sc_buffer
!= NULL
) {
212 stackshot_config
->sc_size
= suggested_size
;
218 * stackshot_config_set_delta_timestamp: set the timestamp to use as the basis for the delta stackshot
220 * This timestamp will be used along with STACKSHOT_COLLECT_DELTA_SNAPSHOT flag to collect delta stackshots
222 * Inputs: stackshot_config - a pointer to a stackshot_config_t
223 * delta_timestamp - timestamp in MachAbsoluteTime units to be used as the basis for a delta stackshot
225 * Outputs: -1 if the passed stackshot config is NULL or there is existing stackshot buffer set.
229 stackshot_config_set_delta_timestamp(stackshot_config_t
*stackshot_config
, uint64_t delta_timestamp
)
231 if (stackshot_config
== NULL
|| (void *)stackshot_config
->sc_buffer
!= NULL
) {
235 stackshot_config
->sc_delta_timestamp
= delta_timestamp
;
241 * stackshot_config_set_pagetable_mask: set the level mask for pagetable dumping
243 * Each bit of the mask corresponds to a level in the paging structure. Bit 0
244 * corresponds to Level 0, bit 1 to level 1, and so on. It is undefined what
245 * happens when a bit is set that's higher than the current maximum level of
246 * pagetable structures.
248 * When using this setter, you must also pass STACKSHOT_PAGE_TABLES as a flag
249 * before invoking stackshot, otherwise this setter is a no-operation.
251 * Inputs: stackshot_config - a pointer to a stackshot_config_t
252 * level_mask - the pagetable level mask, as described above
254 * Outputs: -1 if the passed stackshot config is NULL or there is existing stackshot buffer set.
258 stackshot_config_set_pagetable_mask(stackshot_config_t
*stackshot_config
, uint32_t pagetable_mask
)
260 if (stackshot_config
== NULL
|| (void *)stackshot_config
->sc_buffer
!= NULL
) {
264 stackshot_config
->sc_pagetable_mask
= pagetable_mask
;
271 * stackshot_config_dealloc_buffer: dealloc the stackshot buffer and reset the size so that a
272 * stackshot_config_t can be used again
274 * Inputs: stackshot_config - a pointer to a stackshot_config_t
276 * Outputs: EINVAL if the passed stackshot_config is NULL or if its buffer is NULL
280 stackshot_config_dealloc_buffer(stackshot_config_t
*stackshot_config
)
282 stackshot_config_t
*s_config
;
284 if (stackshot_config
== NULL
) {
287 s_config
= (stackshot_config_t
*) stackshot_config
;
289 if (s_config
->sc_size
&& s_config
->sc_buffer
) {
290 mach_vm_deallocate(mach_task_self(), (mach_vm_offset_t
)s_config
->sc_buffer
, (mach_vm_size_t
)s_config
->sc_size
);
293 s_config
->sc_buffer
= 0;
294 s_config
->sc_size
= 0;
300 * stackshot_config_dealloc: dealloc the stackshot buffer and the stackshot config
302 * Inputs: stackshot_config - a pointer to a stackshot_config_t
304 * Outputs: EINVAL if the passed stackshot_cofnig is NULL
308 stackshot_config_dealloc(stackshot_config_t
*stackshot_config
)
310 stackshot_config_t
*s_config
;
312 if (stackshot_config
== NULL
) {
315 s_config
= (stackshot_config_t
*) stackshot_config
;
317 if (s_config
->sc_size
&& s_config
->sc_buffer
) {
318 mach_vm_deallocate(mach_task_self(), (mach_vm_offset_t
)s_config
->sc_buffer
, (mach_vm_size_t
)s_config
->sc_size
);
321 s_config
->sc_buffer
= 0;
322 s_config
->sc_size
= 0;