1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 * 22 * $FreeBSD$ 23 */ 24 /* 25 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 26 * Use is subject to license terms. 27 */ 28 #include <sys/cdefs.h> 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/kernel.h> 33 #include <sys/stack.h> 34 #include <sys/pcpu.h> 35 36 #include <machine/frame.h> 37 #include <machine/md_var.h> 38 39 #include <vm/vm.h> 40 #include <vm/vm_param.h> 41 #include <vm/pmap.h> 42 43 #include <machine/atomic.h> 44 #include <machine/db_machdep.h> 45 #include <machine/md_var.h> 46 #include <machine/stack.h> 47 #include <ddb/db_sym.h> 48 #include <ddb/ddb.h> 49 #include <sys/kdb.h> 50 51 #include "regset.h" 52 53 /* 54 * Wee need some reasonable default to prevent backtrace code 55 * from wandering too far 56 */ 57 #define MAX_FUNCTION_SIZE 0x10000 58 #define MAX_PROLOGUE_SIZE 0x100 59 #define MAX_USTACK_DEPTH 2048 60 61 uint8_t dtrace_fuword8_nocheck(void *); 62 uint16_t dtrace_fuword16_nocheck(void *); 63 uint32_t dtrace_fuword32_nocheck(void *); 64 uint64_t dtrace_fuword64_nocheck(void *); 65 66 void 67 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, 68 uint32_t *intrpc) 69 { 70 struct unwind_state state; 71 int scp_offset; 72 int depth; 73 74 depth = 0; 75 76 if (intrpc != 0) { 77 pcstack[depth++] = (pc_t) intrpc; 78 } 79 80 aframes++; 81 82 state.fp = (uintptr_t)__builtin_frame_address(0); 83 state.pc = (uintptr_t)dtrace_getpcstack; 84 85 while (depth < pcstack_limit) { 86 if (!unwind_frame(curthread, &state)) 87 break; 88 if (!INKERNEL(state.pc)) 89 break; 90 91 /* 92 * NB: Unlike some other architectures, we don't need to 93 * explicitly insert cpu_dtrace_caller as it appears in the 94 * normal kernel stack trace rather than a special trap frame. 95 */ 96 if (aframes > 0) { 97 aframes--; 98 } else { 99 pcstack[depth++] = state.pc; 100 } 101 102 } 103 104 for (; depth < pcstack_limit; depth++) { 105 pcstack[depth] = 0; 106 } 107 } 108 109 static int 110 dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, 111 uintptr_t fp) 112 { 113 volatile uint16_t *flags = 114 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 115 int ret = 0; 116 uintptr_t oldfp = fp; 117 118 ASSERT(pcstack == NULL || pcstack_limit > 0); 119 120 while (pc != 0) { 121 /* 122 * We limit the number of times we can go around this 123 * loop to account for a circular stack. 124 */ 125 if (ret++ >= MAX_USTACK_DEPTH) { 126 *flags |= CPU_DTRACE_BADSTACK; 127 cpu_core[curcpu].cpuc_dtrace_illval = fp; 128 break; 129 } 130 131 if (pcstack != NULL) { 132 *pcstack++ = (uint64_t)pc; 133 pcstack_limit--; 134 if (pcstack_limit <= 0) 135 break; 136 } 137 138 if (fp == 0) 139 break; 140 141 pc = dtrace_fuword64((void *)(fp + 142 offsetof(struct arm64_frame, f_retaddr))); 143 fp = dtrace_fuword64((void *)fp); 144 145 if (fp == oldfp) { 146 *flags |= CPU_DTRACE_BADSTACK; 147 cpu_core[curcpu].cpuc_dtrace_illval = fp; 148 break; 149 } 150 151 /* 152 * ARM64TODO: 153 * This workaround might not be necessary. It needs to be 154 * revised and removed from all architectures if found 155 * unwanted. Leaving the original x86 comment for reference. 156 * 157 * This is totally bogus: if we faulted, we're going to clear 158 * the fault and break. This is to deal with the apparently 159 * broken Java stacks on x86. 160 */ 161 if (*flags & CPU_DTRACE_FAULT) { 162 *flags &= ~CPU_DTRACE_FAULT; 163 break; 164 } 165 166 oldfp = fp; 167 } 168 169 return (ret); 170 } 171 172 void 173 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) 174 { 175 proc_t *p = curproc; 176 struct trapframe *tf; 177 uintptr_t pc, fp; 178 volatile uint16_t *flags = 179 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 180 int n; 181 182 if (*flags & CPU_DTRACE_FAULT) 183 return; 184 185 if (pcstack_limit <= 0) 186 return; 187 188 /* 189 * If there's no user context we still need to zero the stack. 190 */ 191 if (p == NULL || (tf = curthread->td_frame) == NULL) 192 goto zero; 193 194 *pcstack++ = (uint64_t)p->p_pid; 195 pcstack_limit--; 196 197 if (pcstack_limit <= 0) 198 return; 199 200 pc = tf->tf_elr; 201 fp = tf->tf_x[29]; 202 203 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 204 /* 205 * In an entry probe. The frame pointer has not yet been 206 * pushed (that happens in the function prologue). The 207 * best approach is to add the current pc as a missing top 208 * of stack and back the pc up to the caller, which is stored 209 * at the current stack pointer address since the call 210 * instruction puts it there right before the branch. 211 */ 212 213 *pcstack++ = (uint64_t)pc; 214 pcstack_limit--; 215 if (pcstack_limit <= 0) 216 return; 217 218 pc = tf->tf_lr; 219 } 220 221 n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp); 222 ASSERT(n >= 0); 223 ASSERT(n <= pcstack_limit); 224 225 pcstack += n; 226 pcstack_limit -= n; 227 228 zero: 229 while (pcstack_limit-- > 0) 230 *pcstack++ = 0; 231 } 232 233 int 234 dtrace_getustackdepth(void) 235 { 236 237 printf("IMPLEMENT ME: %s\n", __func__); 238 239 return (0); 240 } 241 242 void 243 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) 244 { 245 246 printf("IMPLEMENT ME: %s\n", __func__); 247 } 248 249 /*ARGSUSED*/ 250 uint64_t 251 dtrace_getarg(int arg, int aframes) 252 { 253 254 printf("IMPLEMENT ME: %s\n", __func__); 255 256 return (0); 257 } 258 259 int 260 dtrace_getstackdepth(int aframes) 261 { 262 struct unwind_state state; 263 int scp_offset; 264 int depth; 265 bool done; 266 267 depth = 1; 268 done = false; 269 270 state.fp = (uintptr_t)__builtin_frame_address(0); 271 state.pc = (uintptr_t)dtrace_getstackdepth; 272 273 do { 274 done = !unwind_frame(curthread, &state); 275 if (!INKERNEL(state.pc) || !INKERNEL(state.fp)) 276 break; 277 depth++; 278 } while (!done); 279 280 if (depth < aframes) 281 return (0); 282 else 283 return (depth - aframes); 284 } 285 286 ulong_t 287 dtrace_getreg(struct trapframe *rp, uint_t reg) 288 { 289 290 printf("IMPLEMENT ME: %s\n", __func__); 291 292 return (0); 293 } 294 295 static int 296 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) 297 { 298 299 if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { 300 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 301 cpu_core[curcpu].cpuc_dtrace_illval = uaddr; 302 return (0); 303 } 304 305 return (1); 306 } 307 308 void 309 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, 310 volatile uint16_t *flags) 311 { 312 313 if (dtrace_copycheck(uaddr, kaddr, size)) 314 dtrace_copy(uaddr, kaddr, size); 315 } 316 317 void 318 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, 319 volatile uint16_t *flags) 320 { 321 322 if (dtrace_copycheck(uaddr, kaddr, size)) 323 dtrace_copy(kaddr, uaddr, size); 324 } 325 326 void 327 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, 328 volatile uint16_t *flags) 329 { 330 331 if (dtrace_copycheck(uaddr, kaddr, size)) 332 dtrace_copystr(uaddr, kaddr, size, flags); 333 } 334 335 void 336 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, 337 volatile uint16_t *flags) 338 { 339 340 if (dtrace_copycheck(uaddr, kaddr, size)) 341 dtrace_copystr(kaddr, uaddr, size, flags); 342 } 343 344 uint8_t 345 dtrace_fuword8(void *uaddr) 346 { 347 348 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 349 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 350 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 351 return (0); 352 } 353 354 return (dtrace_fuword8_nocheck(uaddr)); 355 } 356 357 uint16_t 358 dtrace_fuword16(void *uaddr) 359 { 360 361 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 362 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 363 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 364 return (0); 365 } 366 367 return (dtrace_fuword16_nocheck(uaddr)); 368 } 369 370 uint32_t 371 dtrace_fuword32(void *uaddr) 372 { 373 374 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 375 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 376 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 377 return (0); 378 } 379 380 return (dtrace_fuword32_nocheck(uaddr)); 381 } 382 383 uint64_t 384 dtrace_fuword64(void *uaddr) 385 { 386 387 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 388 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 389 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 390 return (0); 391 } 392 393 return (dtrace_fuword64_nocheck(uaddr)); 394 } 395