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