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/sysent.h> 35 #include <sys/pcpu.h> 36 37 #include <machine/frame.h> 38 #include <machine/md_var.h> 39 #include <machine/reg.h> 40 #include <machine/stack.h> 41 42 #include <vm/vm.h> 43 #include <vm/vm_param.h> 44 #include <vm/pmap.h> 45 46 #include "regset.h" 47 48 uint8_t dtrace_fuword8_nocheck(void *); 49 uint16_t dtrace_fuword16_nocheck(void *); 50 uint32_t dtrace_fuword32_nocheck(void *); 51 uint64_t dtrace_fuword64_nocheck(void *); 52 53 /* Offset to the LR Save word (ppc32) */ 54 #define RETURN_OFFSET 4 55 #define RETURN_OFFSET64 8 56 57 #define INKERNEL(x) ((x) <= VM_MAX_KERNEL_ADDRESS && \ 58 (x) >= VM_MIN_KERNEL_ADDRESS) 59 60 greg_t 61 dtrace_getfp(void) 62 { 63 return (greg_t)__builtin_frame_address(0); 64 } 65 66 void 67 dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, 68 uint32_t *intrpc) 69 { 70 int depth = 0; 71 register_t sp; 72 vm_offset_t callpc; 73 pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; 74 75 if (intrpc != 0) 76 pcstack[depth++] = (pc_t) intrpc; 77 78 aframes++; 79 80 sp = dtrace_getfp(); 81 82 while (depth < pcstack_limit) { 83 if (!INKERNEL((long) sp)) 84 break; 85 86 callpc = *(uintptr_t *)(sp + RETURN_OFFSET); 87 88 if (!INKERNEL(callpc)) 89 break; 90 91 if (aframes > 0) { 92 aframes--; 93 if ((aframes == 0) && (caller != 0)) { 94 pcstack[depth++] = caller; 95 } 96 } 97 else { 98 pcstack[depth++] = callpc; 99 } 100 101 sp = *(uintptr_t*)sp; 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 sp) 112 { 113 proc_t *p = curproc; 114 int ret = 0; 115 116 ASSERT(pcstack == NULL || pcstack_limit > 0); 117 118 while (pc != 0) { 119 ret++; 120 if (pcstack != NULL) { 121 *pcstack++ = (uint64_t)pc; 122 pcstack_limit--; 123 if (pcstack_limit <= 0) 124 break; 125 } 126 127 if (sp == 0) 128 break; 129 130 if (SV_PROC_FLAG(p, SV_ILP32)) { 131 pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET)); 132 sp = dtrace_fuword32((void *)sp); 133 } 134 else { 135 pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64)); 136 sp = dtrace_fuword64((void *)sp); 137 } 138 } 139 140 return (ret); 141 } 142 143 void 144 dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) 145 { 146 proc_t *p = curproc; 147 struct trapframe *tf; 148 uintptr_t pc, sp; 149 volatile uint16_t *flags = 150 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 151 int n; 152 153 if (*flags & CPU_DTRACE_FAULT) 154 return; 155 156 if (pcstack_limit <= 0) 157 return; 158 159 /* 160 * If there's no user context we still need to zero the stack. 161 */ 162 if (p == NULL || (tf = curthread->td_frame) == NULL) 163 goto zero; 164 165 *pcstack++ = (uint64_t)p->p_pid; 166 pcstack_limit--; 167 168 if (pcstack_limit <= 0) 169 return; 170 171 pc = tf->srr0; 172 sp = tf->fixreg[1]; 173 174 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 175 /* 176 * In an entry probe. The frame pointer has not yet been 177 * pushed (that happens in the function prologue). The 178 * best approach is to add the current pc as a missing top 179 * of stack and back the pc up to the caller, which is stored 180 * at the current stack pointer address since the call 181 * instruction puts it there right before the branch. 182 */ 183 184 *pcstack++ = (uint64_t)pc; 185 pcstack_limit--; 186 if (pcstack_limit <= 0) 187 return; 188 189 pc = tf->lr; 190 } 191 192 n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp); 193 ASSERT(n >= 0); 194 ASSERT(n <= pcstack_limit); 195 196 pcstack += n; 197 pcstack_limit -= n; 198 199 zero: 200 while (pcstack_limit-- > 0) 201 *pcstack++ = 0; 202 } 203 204 int 205 dtrace_getustackdepth(void) 206 { 207 proc_t *p = curproc; 208 struct trapframe *tf; 209 uintptr_t pc, sp; 210 int n = 0; 211 212 if (p == NULL || (tf = curthread->td_frame) == NULL) 213 return (0); 214 215 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) 216 return (-1); 217 218 pc = tf->srr0; 219 sp = tf->fixreg[1]; 220 221 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 222 /* 223 * In an entry probe. The frame pointer has not yet been 224 * pushed (that happens in the function prologue). The 225 * best approach is to add the current pc as a missing top 226 * of stack and back the pc up to the caller, which is stored 227 * at the current stack pointer address since the call 228 * instruction puts it there right before the branch. 229 */ 230 231 if (SV_PROC_FLAG(p, SV_ILP32)) { 232 pc = dtrace_fuword32((void *) sp); 233 } 234 else 235 pc = dtrace_fuword64((void *) sp); 236 n++; 237 } 238 239 n += dtrace_getustack_common(NULL, 0, pc, sp); 240 241 return (n); 242 } 243 244 void 245 dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) 246 { 247 proc_t *p = curproc; 248 struct trapframe *tf; 249 uintptr_t pc, sp; 250 volatile uint16_t *flags = 251 (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 252 #ifdef notyet /* XXX signal stack */ 253 uintptr_t oldcontext; 254 size_t s1, s2; 255 #endif 256 257 if (*flags & CPU_DTRACE_FAULT) 258 return; 259 260 if (pcstack_limit <= 0) 261 return; 262 263 /* 264 * If there's no user context we still need to zero the stack. 265 */ 266 if (p == NULL || (tf = curthread->td_frame) == NULL) 267 goto zero; 268 269 *pcstack++ = (uint64_t)p->p_pid; 270 pcstack_limit--; 271 272 if (pcstack_limit <= 0) 273 return; 274 275 pc = tf->srr0; 276 sp = tf->fixreg[1]; 277 278 #ifdef notyet /* XXX signal stack */ 279 oldcontext = lwp->lwp_oldcontext; 280 s1 = sizeof (struct xframe) + 2 * sizeof (long); 281 s2 = s1 + sizeof (siginfo_t); 282 #endif 283 284 if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 285 *pcstack++ = (uint64_t)pc; 286 *fpstack++ = 0; 287 pcstack_limit--; 288 if (pcstack_limit <= 0) 289 return; 290 291 if (SV_PROC_FLAG(p, SV_ILP32)) { 292 pc = dtrace_fuword32((void *)sp); 293 } 294 else { 295 pc = dtrace_fuword64((void *)sp); 296 } 297 } 298 299 while (pc != 0) { 300 *pcstack++ = (uint64_t)pc; 301 *fpstack++ = sp; 302 pcstack_limit--; 303 if (pcstack_limit <= 0) 304 break; 305 306 if (sp == 0) 307 break; 308 309 #ifdef notyet /* XXX signal stack */ 310 if (oldcontext == sp + s1 || oldcontext == sp + s2) { 311 ucontext_t *ucp = (ucontext_t *)oldcontext; 312 greg_t *gregs = ucp->uc_mcontext.gregs; 313 314 sp = dtrace_fulword(&gregs[REG_FP]); 315 pc = dtrace_fulword(&gregs[REG_PC]); 316 317 oldcontext = dtrace_fulword(&ucp->uc_link); 318 } else 319 #endif /* XXX */ 320 { 321 if (SV_PROC_FLAG(p, SV_ILP32)) { 322 pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET)); 323 sp = dtrace_fuword32((void *)sp); 324 } 325 else { 326 pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64)); 327 sp = dtrace_fuword64((void *)sp); 328 } 329 } 330 331 /* 332 * This is totally bogus: if we faulted, we're going to clear 333 * the fault and break. This is to deal with the apparently 334 * broken Java stacks on x86. 335 */ 336 if (*flags & CPU_DTRACE_FAULT) { 337 *flags &= ~CPU_DTRACE_FAULT; 338 break; 339 } 340 } 341 342 zero: 343 while (pcstack_limit-- > 0) 344 *pcstack++ = 0; 345 } 346 347 /*ARGSUSED*/ 348 uint64_t 349 dtrace_getarg(int arg, int aframes) 350 { 351 return (0); 352 } 353 354 #ifdef notyet 355 { 356 int depth = 0; 357 register_t sp; 358 vm_offset_t callpc; 359 pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; 360 361 if (intrpc != 0) 362 pcstack[depth++] = (pc_t) intrpc; 363 364 aframes++; 365 366 sp = dtrace_getfp(); 367 368 while (depth < pcstack_limit) { 369 if (!INKERNEL((long) frame)) 370 break; 371 372 callpc = *(void **)(sp + RETURN_OFFSET); 373 374 if (!INKERNEL(callpc)) 375 break; 376 377 if (aframes > 0) { 378 aframes--; 379 if ((aframes == 0) && (caller != 0)) { 380 pcstack[depth++] = caller; 381 } 382 } 383 else { 384 pcstack[depth++] = callpc; 385 } 386 387 sp = *(void **)sp; 388 } 389 390 for (; depth < pcstack_limit; depth++) { 391 pcstack[depth] = 0; 392 } 393 } 394 #endif 395 396 int 397 dtrace_getstackdepth(int aframes) 398 { 399 int depth = 0; 400 register_t sp; 401 402 aframes++; 403 sp = dtrace_getfp(); 404 depth++; 405 for(;;) { 406 if (!INKERNEL((long) sp)) 407 break; 408 if (!INKERNEL((long) *(void **)sp)) 409 break; 410 depth++; 411 sp = *(uintptr_t *)sp; 412 } 413 if (depth < aframes) 414 return 0; 415 else 416 return depth - aframes; 417 } 418 419 ulong_t 420 dtrace_getreg(struct trapframe *rp, uint_t reg) 421 { 422 if (reg < 32) 423 return (rp->fixreg[reg]); 424 425 switch (reg) { 426 case 33: 427 return (rp->lr); 428 case 34: 429 return (rp->cr); 430 case 35: 431 return (rp->xer); 432 case 36: 433 return (rp->ctr); 434 case 37: 435 return (rp->srr0); 436 case 38: 437 return (rp->srr1); 438 case 39: 439 return (rp->exc); 440 default: 441 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 442 return (0); 443 } 444 } 445 446 static int 447 dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) 448 { 449 ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr); 450 451 if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { 452 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 453 cpu_core[curcpu].cpuc_dtrace_illval = uaddr; 454 return (0); 455 } 456 457 return (1); 458 } 459 460 void 461 dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, 462 volatile uint16_t *flags) 463 { 464 if (dtrace_copycheck(uaddr, kaddr, size)) 465 dtrace_copy(uaddr, kaddr, size); 466 } 467 468 void 469 dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, 470 volatile uint16_t *flags) 471 { 472 if (dtrace_copycheck(uaddr, kaddr, size)) 473 dtrace_copy(kaddr, uaddr, size); 474 } 475 476 void 477 dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, 478 volatile uint16_t *flags) 479 { 480 if (dtrace_copycheck(uaddr, kaddr, size)) 481 dtrace_copystr(uaddr, kaddr, size, flags); 482 } 483 484 void 485 dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, 486 volatile uint16_t *flags) 487 { 488 if (dtrace_copycheck(uaddr, kaddr, size)) 489 dtrace_copystr(kaddr, uaddr, size, flags); 490 } 491 492 uint8_t 493 dtrace_fuword8(void *uaddr) 494 { 495 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 496 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 497 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 498 return (0); 499 } 500 return (dtrace_fuword8_nocheck(uaddr)); 501 } 502 503 uint16_t 504 dtrace_fuword16(void *uaddr) 505 { 506 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 507 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 508 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 509 return (0); 510 } 511 return (dtrace_fuword16_nocheck(uaddr)); 512 } 513 514 uint32_t 515 dtrace_fuword32(void *uaddr) 516 { 517 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 518 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 519 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 520 return (0); 521 } 522 return (dtrace_fuword32_nocheck(uaddr)); 523 } 524 525 uint64_t 526 dtrace_fuword64(void *uaddr) 527 { 528 if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 529 DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 530 cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 531 return (0); 532 } 533 return (dtrace_fuword64_nocheck(uaddr)); 534 } 535