]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/stackshot.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / bsd / kern / stackshot.c
1 /*
2 * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
3 *
4 * @Apple_LICENSE_HEADER_START@
5 *
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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
21 */
22
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>
30
31 /*
32 * Stackshot system calls
33 */
34
35 #if CONFIG_TELEMETRY
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);
40
41 static int
42 stackshot_kern_return_to_bsd_error(kern_return_t kr)
43 {
44 switch (kr) {
45 case KERN_SUCCESS:
46 return 0;
47 case KERN_RESOURCE_SHORTAGE:
48 /* could not allocate memory, or stackshot is actually bigger than
49 * SANE_TRACEBUF_SIZE */
50 return ENOMEM;
51 case KERN_INSUFFICIENT_BUFFER_SIZE:
52 case KERN_NO_SPACE:
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. */
56 return ENOSPC;
57 case KERN_NO_ACCESS:
58 return EPERM;
59 case KERN_MEMORY_PRESENT:
60 return EEXIST;
61 case KERN_NOT_SUPPORTED:
62 return ENOTSUP;
63 case KERN_NOT_IN_SET:
64 /* requested existing buffer, but there isn't one. */
65 return ENOENT;
66 case KERN_ABORTED:
67 /* kdp did not report an error, but also did not produce any data */
68 return EINTR;
69 case KERN_FAILURE:
70 /* stackshot came across inconsistent data and needed to bail out */
71 return EBUSY;
72 case KERN_OPERATION_TIMED_OUT:
73 /* debugger synchronization timed out */
74 return ETIMEDOUT;
75 default:
76 return EINVAL;
77 }
78 }
79
80 /*
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.
84 *
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
99 */
100 int
101 stack_snapshot_with_config(struct proc *p, struct stack_snapshot_with_config_args *uap, __unused int *retval)
102 {
103 int error = 0;
104 kern_return_t kr;
105
106 if ((error = suser(kauth_cred_get(), &p->p_acflag))) {
107 return error;
108 }
109
110 if ((void*)uap->stackshot_config == NULL) {
111 return EINVAL;
112 }
113
114 switch (uap->stackshot_config_version) {
115 case STACKSHOT_CONFIG_TYPE:
116 if (uap->stackshot_config_size != sizeof(stackshot_config_t)) {
117 return EINVAL;
118 }
119 stackshot_config_t config;
120 error = copyin(uap->stackshot_config, &config, sizeof(stackshot_config_t));
121 if (error != KERN_SUCCESS) {
122 return EFAULT;
123 }
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);
126 default:
127 return ENOTSUP;
128 }
129 }
130
131 #if CONFIG_TELEMETRY
132 /*
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
137 * buffer
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
144 * and -1 otherwise.
145 */
146 int
147 microstackshot(struct proc *p, struct microstackshot_args *uap, int32_t *retval)
148 {
149 int error = 0;
150 kern_return_t kr;
151
152 if ((error = suser(kauth_cred_get(), &p->p_acflag))) {
153 return error;
154 }
155
156 kr = stack_microstackshot(uap->tracebuf, uap->tracebuf_size, uap->flags, retval);
157 return stackshot_kern_return_to_bsd_error(kr);
158 }
159 #endif /* CONFIG_TELEMETRY */
160
161 /*
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.
165 *
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
173 */
174 int
175 kern_stack_snapshot_with_reason(__unused char *reason)
176 {
177 stackshot_config_t config;
178 kern_return_t kr;
179
180 config.sc_pid = -1;
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;
187
188 kr = kern_stack_snapshot_internal(STACKSHOT_CONFIG_TYPE, &config, sizeof(stackshot_config_t), FALSE);
189 return stackshot_kern_return_to_bsd_error(kr);
190 }