]>
Commit | Line | Data |
---|---|---|
39037602 A |
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 | if((void*)uap->stackshot_config == NULL) { | |
110 | return EINVAL; | |
111 | } | |
112 | ||
113 | switch (uap->stackshot_config_version) { | |
114 | case STACKSHOT_CONFIG_TYPE: | |
115 | if (uap->stackshot_config_size != sizeof(stackshot_config_t)) { | |
116 | return EINVAL; | |
117 | } | |
118 | stackshot_config_t config; | |
119 | error = copyin(uap->stackshot_config, &config, sizeof(stackshot_config_t)); | |
120 | if (error != KERN_SUCCESS) | |
121 | { | |
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 | kr = stack_microstackshot(uap->tracebuf, uap->tracebuf_size, uap->flags, retval); | |
156 | return stackshot_kern_return_to_bsd_error(kr); | |
157 | } | |
158 | #endif /* CONFIG_TELEMETRY */ | |
159 | ||
160 | /* | |
161 | * kern_stack_snapshot_with_reason: Obtains a coherent set of stack traces for specified threads on the sysem, | |
162 | * tracing both kernel and user stacks where available. Allocates a buffer from the | |
163 | * kernel and stores the address of this buffer. | |
164 | * | |
165 | * Inputs: reason - the reason for triggering a stackshot (unused at the moment, but in the | |
166 | * future will be saved in the stackshot) | |
167 | * Outputs: EINVAL/ENOTSUP if there is a problem with the arguments | |
168 | * EPERM if the caller doesn't pass at least one KERNEL stackshot flag | |
169 | * ENOMEM if the kernel is unable to allocate enough memory to serve the request | |
170 | * ESRCH if the target PID isn't found | |
171 | * returns KERN_SUCCESS on success | |
172 | */ | |
173 | int | |
174 | kern_stack_snapshot_with_reason(__unused char *reason) | |
175 | { | |
176 | stackshot_config_t config; | |
177 | kern_return_t kr; | |
178 | ||
179 | config.sc_pid = -1; | |
180 | config.sc_flags = (STACKSHOT_SAVE_LOADINFO | STACKSHOT_GET_GLOBAL_MEM_STATS | STACKSHOT_SAVE_IN_KERNEL_BUFFER | | |
181 | STACKSHOT_KCDATA_FORMAT | STACKSHOT_ENABLE_UUID_FAULTING); | |
182 | config.sc_delta_timestamp = 0; | |
183 | config.sc_out_buffer_addr = 0; | |
184 | config.sc_out_size_addr = 0; | |
185 | ||
186 | kr = kern_stack_snapshot_internal(STACKSHOT_CONFIG_TYPE, &config, sizeof(stackshot_config_t), FALSE); | |
187 | return stackshot_kern_return_to_bsd_error(kr); | |
188 | } |