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 = fp; 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 oldfp = fp; 173 } 174 175 return (ret); 176 } 177 178 void 179 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) 180 { 181 proc_t *p = curproc; 182 struct trapframe *tf; 183 uintptr_t pc, sp, fp; 184 volatile uint16_t *flags = 185 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 186 int n; 187 188 if (*flags & CPU_DTRACE_FAULT) 189 return; 190 191 if (pcstack_limit <= 0) 192 return; 193 194 /* 195 * If there's no user context we still need to zero the stack. 196 */ 197 if (p == NULL || (tf = curthread->td_frame) == NULL) 198 goto zero; 199 200 *pcstack++ = (uint64_t)p->p_pid; 201 pcstack_limit--; 202 203 if (pcstack_limit <= 0) 204 return; 205 206 pc = tf->tf_elr; 207 sp = tf->tf_sp; 208 fp = tf->tf_x[29]; 209 210 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 211 /* 212 * In an entry probe. The frame pointer has not yet been 213 * pushed (that happens in the function prologue). The 214 * best approach is to add the current pc as a missing top 215 * of stack and back the pc up to the caller, which is stored 216 * at the current stack pointer address since the call 217 * instruction puts it there right before the branch. 218 */ 219 220 *pcstack++ = (uint64_t)pc; 221 pcstack_limit--; 222 if (pcstack_limit <= 0) 223 return; 224 225 pc = tf->tf_lr; 226 } 227 228 n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp); 229 ASSERT(n >= 0); 230 ASSERT(n <= pcstack_limit); 231 232 pcstack += n; 233 pcstack_limit -= n; 234 235 zero: 236 while (pcstack_limit-- > 0) 237 *pcstack++ = 0; 238 } 239 240 int 241 dtrace_getustackdepth(void) 242 { 243 244 printf("IMPLEMENT ME: %s\n", __func__); 245 246 return (0); 247 } 248 249 void 250 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) 251 { 252 253 printf("IMPLEMENT ME: %s\n", __func__); 254 } 255 256 /*ARGSUSED*/ 257 uint64_t 258 dtrace_getarg(int arg, int aframes) 259 { 260 261 printf("IMPLEMENT ME: %s\n", __func__); 262 263 return (0); 264 } 265 266 int 267 dtrace_getstackdepth(int aframes) 268 { 269 struct unwind_state state; 270 int scp_offset; 271 register_t sp; 272 int depth; 273 int done; 274 275 depth = 1; 276 done = 0; 277 278 __asm __volatile("mov %0, sp" : "=&r" (sp)); 279 280 state.fp = (uint64_t)__builtin_frame_address(0); 281 state.sp = sp; 282 state.pc = (uint64_t)dtrace_getstackdepth; 283 284 do { 285 done = unwind_frame(&state); 286 if (!INKERNEL(state.pc) || !INKERNEL(state.fp)) 287 break; 288 depth++; 289 } while (!done); 290 291 if (depth < aframes) 292 return (0); 293 else 294 return (depth - aframes); 295 } 296 297 ulong_t 298 dtrace_getreg(struct trapframe *rp, uint_t reg) 299 { 300 301 printf("IMPLEMENT ME: %s\n", __func__); 302 303 return (0); 304 } 305 306 static int 307 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) 308 { 309 310 if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { 311 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 312 cpu_core[curcpu].cpuc_dtrace_illval = uaddr; 313 return (0); 314 } 315 316 return (1); 317 } 318 319 void 320 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, 321 volatile uint16_t *flags) 322 { 323 324 if (dtrace_copycheck(uaddr, kaddr, size)) 325 dtrace_copy(uaddr, kaddr, size); 326 } 327 328 void 329 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, 330 volatile uint16_t *flags) 331 { 332 333 if (dtrace_copycheck(uaddr, kaddr, size)) 334 dtrace_copy(kaddr, uaddr, size); 335 } 336 337 void 338 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, 339 volatile uint16_t *flags) 340 { 341 342 if (dtrace_copycheck(uaddr, kaddr, size)) 343 dtrace_copystr(uaddr, kaddr, size, flags); 344 } 345 346 void 347 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, 348 volatile uint16_t *flags) 349 { 350 351 if (dtrace_copycheck(uaddr, kaddr, size)) 352 dtrace_copystr(kaddr, uaddr, size, flags); 353 } 354 355 uint8_t 356 dtrace_fuword8(void *uaddr) 357 { 358 359 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 360 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 361 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 362 return (0); 363 } 364 365 return (dtrace_fuword8_nocheck(uaddr)); 366 } 367 368 uint16_t 369 dtrace_fuword16(void *uaddr) 370 { 371 372 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 373 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 374 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 375 return (0); 376 } 377 378 return (dtrace_fuword16_nocheck(uaddr)); 379 } 380 381 uint32_t 382 dtrace_fuword32(void *uaddr) 383 { 384 385 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 386 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 387 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 388 return (0); 389 } 390 391 return (dtrace_fuword32_nocheck(uaddr)); 392 } 393 394 uint64_t 395 dtrace_fuword64(void *uaddr) 396 { 397 398 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 399 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 400 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 401 return (0); 402 } 403 404 return (dtrace_fuword64_nocheck(uaddr)); 405 } 406