2 * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
4 * @Apple_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
23 #include <libkern/libkern.h>
24 #include <mach/mach_types.h>
25 #include <sys/errno.h>
26 #include <sys/kauth.h>
27 #include <sys/proc_internal.h>
28 #include <sys/stackshot.h>
29 #include <sys/sysproto.h>
32 * Stackshot system calls
36 extern kern_return_t
stack_microstackshot(user_addr_t tracebuf
, uint32_t tracebuf_size
, uint32_t flags
, int32_t *retval
);
37 #endif /* CONFIG_TELEMETRY */
38 extern kern_return_t
kern_stack_snapshot_with_reason(char* reason
);
39 extern kern_return_t
kern_stack_snapshot_internal(int stackshot_config_version
, void *stackshot_config
, size_t stackshot_config_size
, boolean_t stackshot_from_user
);
42 stackshot_kern_return_to_bsd_error(kern_return_t kr
)
47 case KERN_RESOURCE_SHORTAGE
:
48 /* could not allocate memory, or stackshot is actually bigger than
49 * SANE_TRACEBUF_SIZE */
51 case KERN_INSUFFICIENT_BUFFER_SIZE
:
53 /* ran out of buffer to write the stackshot. Normally this error
54 * causes a larger buffer to be allocated in-kernel, rather than
55 * being returned to the user. */
59 case KERN_MEMORY_PRESENT
:
61 case KERN_NOT_SUPPORTED
:
64 /* requested existing buffer, but there isn't one. */
67 /* kdp did not report an error, but also did not produce any data */
70 /* stackshot came across inconsistent data and needed to bail out */
72 case KERN_OPERATION_TIMED_OUT
:
73 /* debugger synchronization timed out */
81 * stack_snapshot_with_config: Obtains a coherent set of stack traces for specified threads on the sysem,
82 * tracing both kernel and user stacks where available. Allocates a buffer from the
83 * kernel and maps the buffer into the calling task's address space.
85 * Inputs: uap->stackshot_config_version - version of the stackshot config that is being passed
86 * uap->stackshot_config - pointer to the stackshot config
87 * uap->stackshot_config_size- size of the stackshot config being passed
88 * Outputs: EINVAL if there is a problem with the arguments
89 * EFAULT if we failed to copy in the arguments succesfully
90 * EPERM if the caller is not privileged
91 * ENOTSUP if the caller is passing a version of arguments that is not supported by the kernel
92 * (indicates libsyscall:kernel mismatch) or if the caller is requesting unsupported flags
93 * ENOENT if the caller is requesting an existing buffer that doesn't exist or if the
94 * requested PID isn't found
95 * ENOMEM if the kernel is unable to allocate enough memory to serve the request
96 * ENOSPC if there isn't enough space in the caller's address space to remap the buffer
97 * ESRCH if the target PID isn't found
98 * returns KERN_SUCCESS on success
101 stack_snapshot_with_config(struct proc
*p
, struct stack_snapshot_with_config_args
*uap
, __unused
int *retval
)
106 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
))) {
110 if ((void*)uap
->stackshot_config
== NULL
) {
114 switch (uap
->stackshot_config_version
) {
115 case STACKSHOT_CONFIG_TYPE
:
116 if (uap
->stackshot_config_size
!= sizeof(stackshot_config_t
)) {
119 stackshot_config_t config
;
120 error
= copyin(uap
->stackshot_config
, &config
, sizeof(stackshot_config_t
));
121 if (error
!= KERN_SUCCESS
) {
124 kr
= kern_stack_snapshot_internal(uap
->stackshot_config_version
, &config
, sizeof(stackshot_config_t
), TRUE
);
125 return stackshot_kern_return_to_bsd_error(kr
);
133 * microstackshot: Catch all system call for microstackshot related operations, including
134 * enabling/disabling both global and windowed microstackshots as well
135 * as retrieving windowed or global stackshots and the boot profile.
136 * Inputs: uap->tracebuf - address of the user space destination
138 * uap->tracebuf_size - size of the user space trace buffer
139 * uap->flags - various flags
140 * Outputs: EPERM if the caller is not privileged
141 * EINVAL if the supplied mss_args is NULL, mss_args.tracebuf is NULL or mss_args.tracebuf_size is not sane
142 * ENOMEM if we don't have enough memory to satisfy the request
143 * *retval contains the number of bytes traced, if successful
147 microstackshot(struct proc
*p
, struct microstackshot_args
*uap
, int32_t *retval
)
152 if ((error
= suser(kauth_cred_get(), &p
->p_acflag
))) {
156 kr
= stack_microstackshot(uap
->tracebuf
, uap
->tracebuf_size
, uap
->flags
, retval
);
157 return stackshot_kern_return_to_bsd_error(kr
);
159 #endif /* CONFIG_TELEMETRY */
162 * kern_stack_snapshot_with_reason: Obtains a coherent set of stack traces for specified threads on the sysem,
163 * tracing both kernel and user stacks where available. Allocates a buffer from the
164 * kernel and stores the address of this buffer.
166 * Inputs: reason - the reason for triggering a stackshot (unused at the moment, but in the
167 * future will be saved in the stackshot)
168 * Outputs: EINVAL/ENOTSUP if there is a problem with the arguments
169 * EPERM if the caller doesn't pass at least one KERNEL stackshot flag
170 * ENOMEM if the kernel is unable to allocate enough memory to serve the request
171 * ESRCH if the target PID isn't found
172 * returns KERN_SUCCESS on success
175 kern_stack_snapshot_with_reason(__unused
char *reason
)
177 stackshot_config_t config
;
181 config
.sc_flags
= (STACKSHOT_SAVE_LOADINFO
| STACKSHOT_GET_GLOBAL_MEM_STATS
| STACKSHOT_SAVE_IN_KERNEL_BUFFER
|
182 STACKSHOT_KCDATA_FORMAT
| STACKSHOT_ENABLE_UUID_FAULTING
| STACKSHOT_ENABLE_BT_FAULTING
| STACKSHOT_THREAD_WAITINFO
|
183 STACKSHOT_NO_IO_STATS
| STACKSHOT_COLLECT_SHAREDCACHE_LAYOUT
);
184 config
.sc_delta_timestamp
= 0;
185 config
.sc_out_buffer_addr
= 0;
186 config
.sc_out_size_addr
= 0;
188 kr
= kern_stack_snapshot_internal(STACKSHOT_CONFIG_TYPE
, &config
, sizeof(stackshot_config_t
), FALSE
);
189 return stackshot_kern_return_to_bsd_error(kr
);