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