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