1c7570492SJustin Hibbits /* 2c7570492SJustin Hibbits * CDDL HEADER START 3c7570492SJustin Hibbits * 4c7570492SJustin Hibbits * The contents of this file are subject to the terms of the 5c7570492SJustin Hibbits * Common Development and Distribution License, Version 1.0 only 6c7570492SJustin Hibbits * (the "License"). You may not use this file except in compliance 7c7570492SJustin Hibbits * with the License. 8c7570492SJustin Hibbits * 9c7570492SJustin Hibbits * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10c7570492SJustin Hibbits * or http://www.opensolaris.org/os/licensing. 11c7570492SJustin Hibbits * See the License for the specific language governing permissions 12c7570492SJustin Hibbits * and limitations under the License. 13c7570492SJustin Hibbits * 14c7570492SJustin Hibbits * When distributing Covered Code, include this CDDL HEADER in each 15c7570492SJustin Hibbits * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16c7570492SJustin Hibbits * If applicable, add the following below this CDDL HEADER, with the 17c7570492SJustin Hibbits * fields enclosed by brackets "[]" replaced with your own identifying 18c7570492SJustin Hibbits * information: Portions Copyright [yyyy] [name of copyright owner] 19c7570492SJustin Hibbits * 20c7570492SJustin Hibbits * CDDL HEADER END 21c7570492SJustin Hibbits * 227e7a9efdSJustin Hibbits * Portions Copyright 2012,2013 Justin Hibbits <jhibbits@freebsd.org> 237e7a9efdSJustin Hibbits * 24c7570492SJustin Hibbits * $FreeBSD$ 25c7570492SJustin Hibbits */ 26c7570492SJustin Hibbits /* 27c7570492SJustin Hibbits * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 28c7570492SJustin Hibbits * Use is subject to license terms. 29c7570492SJustin Hibbits */ 30c7570492SJustin Hibbits #include <sys/cdefs.h> 31c7570492SJustin Hibbits 32c7570492SJustin Hibbits #include <sys/param.h> 33c7570492SJustin Hibbits #include <sys/systm.h> 34c7570492SJustin Hibbits #include <sys/kernel.h> 35c7570492SJustin Hibbits #include <sys/stack.h> 36c7570492SJustin Hibbits #include <sys/sysent.h> 37c7570492SJustin Hibbits #include <sys/pcpu.h> 38c7570492SJustin Hibbits 39c7570492SJustin Hibbits #include <machine/frame.h> 40c7570492SJustin Hibbits #include <machine/md_var.h> 41*675cad71SJustin Hibbits #include <machine/psl.h> 42c7570492SJustin Hibbits #include <machine/reg.h> 43c7570492SJustin Hibbits #include <machine/stack.h> 44c7570492SJustin Hibbits 45c7570492SJustin Hibbits #include <vm/vm.h> 46c7570492SJustin Hibbits #include <vm/vm_param.h> 47c7570492SJustin Hibbits #include <vm/pmap.h> 48c7570492SJustin Hibbits 49c7570492SJustin Hibbits #include "regset.h" 50c7570492SJustin Hibbits 51c7570492SJustin Hibbits /* Offset to the LR Save word (ppc32) */ 52c7570492SJustin Hibbits #define RETURN_OFFSET 4 53594ce9adSJustin Hibbits /* Offset to LR Save word (ppc64). CR Save area sits between back chain and LR */ 54594ce9adSJustin Hibbits #define RETURN_OFFSET64 16 55c7570492SJustin Hibbits 56e40a5cd3SJustin Hibbits #ifdef __powerpc64__ 57e40a5cd3SJustin Hibbits #define OFFSET 4 /* Account for the TOC reload slot */ 58*675cad71SJustin Hibbits #define FRAME_OFFSET 48 59e40a5cd3SJustin Hibbits #else 60e40a5cd3SJustin Hibbits #define OFFSET 0 61*675cad71SJustin Hibbits #define FRAME_OFFSET 8 62e40a5cd3SJustin Hibbits #endif 63e40a5cd3SJustin Hibbits 64c7570492SJustin Hibbits #define INKERNEL(x) ((x) <= VM_MAX_KERNEL_ADDRESS && \ 65c7570492SJustin Hibbits (x) >= VM_MIN_KERNEL_ADDRESS) 66c7570492SJustin Hibbits 67e40a5cd3SJustin Hibbits static __inline int 68*675cad71SJustin Hibbits dtrace_sp_inkernel(uintptr_t sp) 69e40a5cd3SJustin Hibbits { 70*675cad71SJustin Hibbits struct trapframe *frame; 71e40a5cd3SJustin Hibbits vm_offset_t callpc; 72e40a5cd3SJustin Hibbits 73e40a5cd3SJustin Hibbits #ifdef __powerpc64__ 74e40a5cd3SJustin Hibbits callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64); 75e40a5cd3SJustin Hibbits #else 76e40a5cd3SJustin Hibbits callpc = *(vm_offset_t *)(sp + RETURN_OFFSET); 77e40a5cd3SJustin Hibbits #endif 78e40a5cd3SJustin Hibbits if ((callpc & 3) || (callpc < 0x100)) 79e40a5cd3SJustin Hibbits return (0); 80e40a5cd3SJustin Hibbits 81e40a5cd3SJustin Hibbits /* 82e40a5cd3SJustin Hibbits * trapexit() and asttrapexit() are sentinels 83e40a5cd3SJustin Hibbits * for kernel stack tracing. 84e40a5cd3SJustin Hibbits */ 85*675cad71SJustin Hibbits if (callpc + OFFSET == (vm_offset_t) &trapexit || 86*675cad71SJustin Hibbits callpc + OFFSET == (vm_offset_t) &asttrapexit) { 87*675cad71SJustin Hibbits if (sp == 0) 88e40a5cd3SJustin Hibbits return (0); 89*675cad71SJustin Hibbits frame = (struct trapframe *)(sp + FRAME_OFFSET); 90*675cad71SJustin Hibbits 91*675cad71SJustin Hibbits return ((frame->srr1 & PSL_PR) == 0); 92*675cad71SJustin Hibbits } 93e40a5cd3SJustin Hibbits 94e40a5cd3SJustin Hibbits return (1); 95e40a5cd3SJustin Hibbits } 96e40a5cd3SJustin Hibbits 97e40a5cd3SJustin Hibbits static __inline uintptr_t 98e40a5cd3SJustin Hibbits dtrace_next_sp(uintptr_t sp) 99e40a5cd3SJustin Hibbits { 100e40a5cd3SJustin Hibbits vm_offset_t callpc; 101*675cad71SJustin Hibbits struct trapframe *frame; 102e40a5cd3SJustin Hibbits 103e40a5cd3SJustin Hibbits #ifdef __powerpc64__ 104e40a5cd3SJustin Hibbits callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64); 105e40a5cd3SJustin Hibbits #else 106e40a5cd3SJustin Hibbits callpc = *(vm_offset_t *)(sp + RETURN_OFFSET); 107e40a5cd3SJustin Hibbits #endif 108e40a5cd3SJustin Hibbits 109e40a5cd3SJustin Hibbits /* 110e40a5cd3SJustin Hibbits * trapexit() and asttrapexit() are sentinels 111e40a5cd3SJustin Hibbits * for kernel stack tracing. 112e40a5cd3SJustin Hibbits */ 113e40a5cd3SJustin Hibbits if ((callpc + OFFSET == (vm_offset_t) &trapexit || 114*675cad71SJustin Hibbits callpc + OFFSET == (vm_offset_t) &asttrapexit)) { 115e40a5cd3SJustin Hibbits /* Access the trap frame */ 116*675cad71SJustin Hibbits frame = (struct trapframe *)(sp + FRAME_OFFSET); 117*675cad71SJustin Hibbits return (*(uintptr_t *)(frame->fixreg[1])); 118*675cad71SJustin Hibbits } 119e40a5cd3SJustin Hibbits 120e40a5cd3SJustin Hibbits return (*(uintptr_t*)sp); 121e40a5cd3SJustin Hibbits } 122e40a5cd3SJustin Hibbits 123e40a5cd3SJustin Hibbits static __inline uintptr_t 124e40a5cd3SJustin Hibbits dtrace_get_pc(uintptr_t sp) 125e40a5cd3SJustin Hibbits { 126*675cad71SJustin Hibbits struct trapframe *frame; 127e40a5cd3SJustin Hibbits vm_offset_t callpc; 128e40a5cd3SJustin Hibbits 129e40a5cd3SJustin Hibbits #ifdef __powerpc64__ 130e40a5cd3SJustin Hibbits callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64); 131e40a5cd3SJustin Hibbits #else 132e40a5cd3SJustin Hibbits callpc = *(vm_offset_t *)(sp + RETURN_OFFSET); 133e40a5cd3SJustin Hibbits #endif 134e40a5cd3SJustin Hibbits 135e40a5cd3SJustin Hibbits /* 136e40a5cd3SJustin Hibbits * trapexit() and asttrapexit() are sentinels 137e40a5cd3SJustin Hibbits * for kernel stack tracing. 138e40a5cd3SJustin Hibbits */ 139e40a5cd3SJustin Hibbits if ((callpc + OFFSET == (vm_offset_t) &trapexit || 140*675cad71SJustin Hibbits callpc + OFFSET == (vm_offset_t) &asttrapexit)) { 141e40a5cd3SJustin Hibbits /* Access the trap frame */ 142*675cad71SJustin Hibbits frame = (struct trapframe *)(sp + FRAME_OFFSET); 143*675cad71SJustin Hibbits return (frame->srr0); 144*675cad71SJustin Hibbits } 145e40a5cd3SJustin Hibbits 146e40a5cd3SJustin Hibbits return (callpc); 147e40a5cd3SJustin Hibbits } 148e40a5cd3SJustin Hibbits 149c7570492SJustin Hibbits greg_t 150c7570492SJustin Hibbits dtrace_getfp(void) 151c7570492SJustin Hibbits { 152c7570492SJustin Hibbits return (greg_t)__builtin_frame_address(0); 153c7570492SJustin Hibbits } 154c7570492SJustin Hibbits 155c7570492SJustin Hibbits void 156c7570492SJustin Hibbits dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, 157c7570492SJustin Hibbits uint32_t *intrpc) 158c7570492SJustin Hibbits { 159c7570492SJustin Hibbits int depth = 0; 160e40a5cd3SJustin Hibbits uintptr_t osp, sp; 161c7570492SJustin Hibbits vm_offset_t callpc; 162c7570492SJustin Hibbits pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; 163c7570492SJustin Hibbits 164e40a5cd3SJustin Hibbits osp = PAGE_SIZE; 165c7570492SJustin Hibbits if (intrpc != 0) 166c7570492SJustin Hibbits pcstack[depth++] = (pc_t) intrpc; 167c7570492SJustin Hibbits 168c7570492SJustin Hibbits aframes++; 169c7570492SJustin Hibbits 170c7570492SJustin Hibbits sp = dtrace_getfp(); 171c7570492SJustin Hibbits 172c7570492SJustin Hibbits while (depth < pcstack_limit) { 173e40a5cd3SJustin Hibbits if (sp <= osp) 174c7570492SJustin Hibbits break; 175c7570492SJustin Hibbits 176*675cad71SJustin Hibbits if (!dtrace_sp_inkernel(sp)) 177c7570492SJustin Hibbits break; 178e40a5cd3SJustin Hibbits callpc = dtrace_get_pc(sp); 179c7570492SJustin Hibbits 180c7570492SJustin Hibbits if (aframes > 0) { 181c7570492SJustin Hibbits aframes--; 182c7570492SJustin Hibbits if ((aframes == 0) && (caller != 0)) { 183c7570492SJustin Hibbits pcstack[depth++] = caller; 184c7570492SJustin Hibbits } 185c7570492SJustin Hibbits } 186c7570492SJustin Hibbits else { 187c7570492SJustin Hibbits pcstack[depth++] = callpc; 188c7570492SJustin Hibbits } 189c7570492SJustin Hibbits 190e40a5cd3SJustin Hibbits osp = sp; 191e40a5cd3SJustin Hibbits sp = dtrace_next_sp(sp); 192c7570492SJustin Hibbits } 193c7570492SJustin Hibbits 194c7570492SJustin Hibbits for (; depth < pcstack_limit; depth++) { 195c7570492SJustin Hibbits pcstack[depth] = 0; 196c7570492SJustin Hibbits } 197c7570492SJustin Hibbits } 198c7570492SJustin Hibbits 199c7570492SJustin Hibbits static int 200c7570492SJustin Hibbits dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, 201c7570492SJustin Hibbits uintptr_t sp) 202c7570492SJustin Hibbits { 203c7570492SJustin Hibbits proc_t *p = curproc; 204c7570492SJustin Hibbits int ret = 0; 205c7570492SJustin Hibbits 206c7570492SJustin Hibbits ASSERT(pcstack == NULL || pcstack_limit > 0); 207c7570492SJustin Hibbits 208c7570492SJustin Hibbits while (pc != 0) { 209c7570492SJustin Hibbits ret++; 210c7570492SJustin Hibbits if (pcstack != NULL) { 211c7570492SJustin Hibbits *pcstack++ = (uint64_t)pc; 212c7570492SJustin Hibbits pcstack_limit--; 213c7570492SJustin Hibbits if (pcstack_limit <= 0) 214c7570492SJustin Hibbits break; 215c7570492SJustin Hibbits } 216c7570492SJustin Hibbits 217c7570492SJustin Hibbits if (sp == 0) 218c7570492SJustin Hibbits break; 219c7570492SJustin Hibbits 220c7570492SJustin Hibbits if (SV_PROC_FLAG(p, SV_ILP32)) { 221c7570492SJustin Hibbits pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET)); 222c7570492SJustin Hibbits sp = dtrace_fuword32((void *)sp); 223c7570492SJustin Hibbits } 224c7570492SJustin Hibbits else { 225c7570492SJustin Hibbits pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64)); 226c7570492SJustin Hibbits sp = dtrace_fuword64((void *)sp); 227c7570492SJustin Hibbits } 228c7570492SJustin Hibbits } 229c7570492SJustin Hibbits 230c7570492SJustin Hibbits return (ret); 231c7570492SJustin Hibbits } 232c7570492SJustin Hibbits 233c7570492SJustin Hibbits void 234c7570492SJustin Hibbits dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) 235c7570492SJustin Hibbits { 236c7570492SJustin Hibbits proc_t *p = curproc; 237c7570492SJustin Hibbits struct trapframe *tf; 238c7570492SJustin Hibbits uintptr_t pc, sp; 239c7570492SJustin Hibbits volatile uint16_t *flags = 240c7570492SJustin Hibbits (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 241c7570492SJustin Hibbits int n; 242c7570492SJustin Hibbits 243c7570492SJustin Hibbits if (*flags & CPU_DTRACE_FAULT) 244c7570492SJustin Hibbits return; 245c7570492SJustin Hibbits 246c7570492SJustin Hibbits if (pcstack_limit <= 0) 247c7570492SJustin Hibbits return; 248c7570492SJustin Hibbits 249c7570492SJustin Hibbits /* 250c7570492SJustin Hibbits * If there's no user context we still need to zero the stack. 251c7570492SJustin Hibbits */ 252c7570492SJustin Hibbits if (p == NULL || (tf = curthread->td_frame) == NULL) 253c7570492SJustin Hibbits goto zero; 254c7570492SJustin Hibbits 255c7570492SJustin Hibbits *pcstack++ = (uint64_t)p->p_pid; 256c7570492SJustin Hibbits pcstack_limit--; 257c7570492SJustin Hibbits 258c7570492SJustin Hibbits if (pcstack_limit <= 0) 259c7570492SJustin Hibbits return; 260c7570492SJustin Hibbits 261c7570492SJustin Hibbits pc = tf->srr0; 262c7570492SJustin Hibbits sp = tf->fixreg[1]; 263c7570492SJustin Hibbits 264c7570492SJustin Hibbits if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 265c7570492SJustin Hibbits /* 266c7570492SJustin Hibbits * In an entry probe. The frame pointer has not yet been 267c7570492SJustin Hibbits * pushed (that happens in the function prologue). The 268c7570492SJustin Hibbits * best approach is to add the current pc as a missing top 269c7570492SJustin Hibbits * of stack and back the pc up to the caller, which is stored 270c7570492SJustin Hibbits * at the current stack pointer address since the call 271c7570492SJustin Hibbits * instruction puts it there right before the branch. 272c7570492SJustin Hibbits */ 273c7570492SJustin Hibbits 274c7570492SJustin Hibbits *pcstack++ = (uint64_t)pc; 275c7570492SJustin Hibbits pcstack_limit--; 276c7570492SJustin Hibbits if (pcstack_limit <= 0) 277c7570492SJustin Hibbits return; 278c7570492SJustin Hibbits 279c7570492SJustin Hibbits pc = tf->lr; 280c7570492SJustin Hibbits } 281c7570492SJustin Hibbits 282c7570492SJustin Hibbits n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp); 283c7570492SJustin Hibbits ASSERT(n >= 0); 284c7570492SJustin Hibbits ASSERT(n <= pcstack_limit); 285c7570492SJustin Hibbits 286c7570492SJustin Hibbits pcstack += n; 287c7570492SJustin Hibbits pcstack_limit -= n; 288c7570492SJustin Hibbits 289c7570492SJustin Hibbits zero: 290c7570492SJustin Hibbits while (pcstack_limit-- > 0) 291c7570492SJustin Hibbits *pcstack++ = 0; 292c7570492SJustin Hibbits } 293c7570492SJustin Hibbits 294c7570492SJustin Hibbits int 295c7570492SJustin Hibbits dtrace_getustackdepth(void) 296c7570492SJustin Hibbits { 297c7570492SJustin Hibbits proc_t *p = curproc; 298c7570492SJustin Hibbits struct trapframe *tf; 299c7570492SJustin Hibbits uintptr_t pc, sp; 300c7570492SJustin Hibbits int n = 0; 301c7570492SJustin Hibbits 302c7570492SJustin Hibbits if (p == NULL || (tf = curthread->td_frame) == NULL) 303c7570492SJustin Hibbits return (0); 304c7570492SJustin Hibbits 305c7570492SJustin Hibbits if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) 306c7570492SJustin Hibbits return (-1); 307c7570492SJustin Hibbits 308c7570492SJustin Hibbits pc = tf->srr0; 309c7570492SJustin Hibbits sp = tf->fixreg[1]; 310c7570492SJustin Hibbits 311c7570492SJustin Hibbits if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 312c7570492SJustin Hibbits /* 313c7570492SJustin Hibbits * In an entry probe. The frame pointer has not yet been 314c7570492SJustin Hibbits * pushed (that happens in the function prologue). The 315c7570492SJustin Hibbits * best approach is to add the current pc as a missing top 316c7570492SJustin Hibbits * of stack and back the pc up to the caller, which is stored 317c7570492SJustin Hibbits * at the current stack pointer address since the call 318c7570492SJustin Hibbits * instruction puts it there right before the branch. 319c7570492SJustin Hibbits */ 320c7570492SJustin Hibbits 321c7570492SJustin Hibbits if (SV_PROC_FLAG(p, SV_ILP32)) { 322c7570492SJustin Hibbits pc = dtrace_fuword32((void *) sp); 323c7570492SJustin Hibbits } 324c7570492SJustin Hibbits else 325c7570492SJustin Hibbits pc = dtrace_fuword64((void *) sp); 326c7570492SJustin Hibbits n++; 327c7570492SJustin Hibbits } 328c7570492SJustin Hibbits 329c7570492SJustin Hibbits n += dtrace_getustack_common(NULL, 0, pc, sp); 330c7570492SJustin Hibbits 331c7570492SJustin Hibbits return (n); 332c7570492SJustin Hibbits } 333c7570492SJustin Hibbits 334c7570492SJustin Hibbits void 335c7570492SJustin Hibbits dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) 336c7570492SJustin Hibbits { 337c7570492SJustin Hibbits proc_t *p = curproc; 338c7570492SJustin Hibbits struct trapframe *tf; 339c7570492SJustin Hibbits uintptr_t pc, sp; 340c7570492SJustin Hibbits volatile uint16_t *flags = 341c7570492SJustin Hibbits (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 342c7570492SJustin Hibbits #ifdef notyet /* XXX signal stack */ 343c7570492SJustin Hibbits uintptr_t oldcontext; 344c7570492SJustin Hibbits size_t s1, s2; 345c7570492SJustin Hibbits #endif 346c7570492SJustin Hibbits 347c7570492SJustin Hibbits if (*flags & CPU_DTRACE_FAULT) 348c7570492SJustin Hibbits return; 349c7570492SJustin Hibbits 350c7570492SJustin Hibbits if (pcstack_limit <= 0) 351c7570492SJustin Hibbits return; 352c7570492SJustin Hibbits 353c7570492SJustin Hibbits /* 354c7570492SJustin Hibbits * If there's no user context we still need to zero the stack. 355c7570492SJustin Hibbits */ 356c7570492SJustin Hibbits if (p == NULL || (tf = curthread->td_frame) == NULL) 357c7570492SJustin Hibbits goto zero; 358c7570492SJustin Hibbits 359c7570492SJustin Hibbits *pcstack++ = (uint64_t)p->p_pid; 360c7570492SJustin Hibbits pcstack_limit--; 361c7570492SJustin Hibbits 362c7570492SJustin Hibbits if (pcstack_limit <= 0) 363c7570492SJustin Hibbits return; 364c7570492SJustin Hibbits 365c7570492SJustin Hibbits pc = tf->srr0; 366c7570492SJustin Hibbits sp = tf->fixreg[1]; 367c7570492SJustin Hibbits 368c7570492SJustin Hibbits #ifdef notyet /* XXX signal stack */ 369c7570492SJustin Hibbits oldcontext = lwp->lwp_oldcontext; 370c7570492SJustin Hibbits s1 = sizeof (struct xframe) + 2 * sizeof (long); 371c7570492SJustin Hibbits s2 = s1 + sizeof (siginfo_t); 372c7570492SJustin Hibbits #endif 373c7570492SJustin Hibbits 374c7570492SJustin Hibbits if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 375c7570492SJustin Hibbits *pcstack++ = (uint64_t)pc; 376c7570492SJustin Hibbits *fpstack++ = 0; 377c7570492SJustin Hibbits pcstack_limit--; 378c7570492SJustin Hibbits if (pcstack_limit <= 0) 379c7570492SJustin Hibbits return; 380c7570492SJustin Hibbits 381c7570492SJustin Hibbits if (SV_PROC_FLAG(p, SV_ILP32)) { 382c7570492SJustin Hibbits pc = dtrace_fuword32((void *)sp); 383c7570492SJustin Hibbits } 384c7570492SJustin Hibbits else { 385c7570492SJustin Hibbits pc = dtrace_fuword64((void *)sp); 386c7570492SJustin Hibbits } 387c7570492SJustin Hibbits } 388c7570492SJustin Hibbits 389c7570492SJustin Hibbits while (pc != 0) { 390c7570492SJustin Hibbits *pcstack++ = (uint64_t)pc; 391c7570492SJustin Hibbits *fpstack++ = sp; 392c7570492SJustin Hibbits pcstack_limit--; 393c7570492SJustin Hibbits if (pcstack_limit <= 0) 394c7570492SJustin Hibbits break; 395c7570492SJustin Hibbits 396c7570492SJustin Hibbits if (sp == 0) 397c7570492SJustin Hibbits break; 398c7570492SJustin Hibbits 399c7570492SJustin Hibbits #ifdef notyet /* XXX signal stack */ 400c7570492SJustin Hibbits if (oldcontext == sp + s1 || oldcontext == sp + s2) { 401c7570492SJustin Hibbits ucontext_t *ucp = (ucontext_t *)oldcontext; 402c7570492SJustin Hibbits greg_t *gregs = ucp->uc_mcontext.gregs; 403c7570492SJustin Hibbits 404c7570492SJustin Hibbits sp = dtrace_fulword(&gregs[REG_FP]); 405c7570492SJustin Hibbits pc = dtrace_fulword(&gregs[REG_PC]); 406c7570492SJustin Hibbits 407c7570492SJustin Hibbits oldcontext = dtrace_fulword(&ucp->uc_link); 408c7570492SJustin Hibbits } else 409c7570492SJustin Hibbits #endif /* XXX */ 410c7570492SJustin Hibbits { 411c7570492SJustin Hibbits if (SV_PROC_FLAG(p, SV_ILP32)) { 412c7570492SJustin Hibbits pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET)); 413c7570492SJustin Hibbits sp = dtrace_fuword32((void *)sp); 414c7570492SJustin Hibbits } 415c7570492SJustin Hibbits else { 416c7570492SJustin Hibbits pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64)); 417c7570492SJustin Hibbits sp = dtrace_fuword64((void *)sp); 418c7570492SJustin Hibbits } 419c7570492SJustin Hibbits } 420c7570492SJustin Hibbits 421c7570492SJustin Hibbits /* 422c7570492SJustin Hibbits * This is totally bogus: if we faulted, we're going to clear 423c7570492SJustin Hibbits * the fault and break. This is to deal with the apparently 424c7570492SJustin Hibbits * broken Java stacks on x86. 425c7570492SJustin Hibbits */ 426c7570492SJustin Hibbits if (*flags & CPU_DTRACE_FAULT) { 427c7570492SJustin Hibbits *flags &= ~CPU_DTRACE_FAULT; 428c7570492SJustin Hibbits break; 429c7570492SJustin Hibbits } 430c7570492SJustin Hibbits } 431c7570492SJustin Hibbits 432c7570492SJustin Hibbits zero: 433c7570492SJustin Hibbits while (pcstack_limit-- > 0) 434c7570492SJustin Hibbits *pcstack++ = 0; 435c7570492SJustin Hibbits } 436c7570492SJustin Hibbits 437c7570492SJustin Hibbits /*ARGSUSED*/ 438c7570492SJustin Hibbits uint64_t 439c7570492SJustin Hibbits dtrace_getarg(int arg, int aframes) 440c7570492SJustin Hibbits { 441f0bd82a1SJustin Hibbits uintptr_t val; 442f0bd82a1SJustin Hibbits uintptr_t *fp = (uintptr_t *)dtrace_getfp(); 443f0bd82a1SJustin Hibbits uintptr_t *stack; 444f0bd82a1SJustin Hibbits int i; 445f0bd82a1SJustin Hibbits 446f0bd82a1SJustin Hibbits /* 447f0bd82a1SJustin Hibbits * A total of 8 arguments are passed via registers; any argument with 448f0bd82a1SJustin Hibbits * index of 7 or lower is therefore in a register. 449f0bd82a1SJustin Hibbits */ 450f0bd82a1SJustin Hibbits int inreg = 7; 451f0bd82a1SJustin Hibbits 452f0bd82a1SJustin Hibbits for (i = 1; i <= aframes; i++) { 453f0bd82a1SJustin Hibbits fp = (uintptr_t *)*fp; 454f0bd82a1SJustin Hibbits 455f0bd82a1SJustin Hibbits /* 456f0bd82a1SJustin Hibbits * On ppc32 AIM, and booke, trapexit() is the immediately following 457f0bd82a1SJustin Hibbits * label. On ppc64 AIM trapexit() follows a nop. 458f0bd82a1SJustin Hibbits */ 459e40a5cd3SJustin Hibbits #ifdef __powerpc64__ 460e40a5cd3SJustin Hibbits if ((long)(fp[2]) + 4 == (long)trapexit) { 461e40a5cd3SJustin Hibbits #else 462e40a5cd3SJustin Hibbits if ((long)(fp[1]) == (long)trapexit) { 463e40a5cd3SJustin Hibbits #endif 464f0bd82a1SJustin Hibbits /* 465f0bd82a1SJustin Hibbits * In the case of powerpc, we will use the pointer to the regs 466f0bd82a1SJustin Hibbits * structure that was pushed when we took the trap. To get this 467f0bd82a1SJustin Hibbits * structure, we must increment beyond the frame structure. If the 468f0bd82a1SJustin Hibbits * argument that we're seeking is passed on the stack, we'll pull 469f0bd82a1SJustin Hibbits * the true stack pointer out of the saved registers and decrement 470f0bd82a1SJustin Hibbits * our argument by the number of arguments passed in registers; if 471f0bd82a1SJustin Hibbits * the argument we're seeking is passed in regsiters, we can just 472f0bd82a1SJustin Hibbits * load it directly. 473f0bd82a1SJustin Hibbits */ 474f0bd82a1SJustin Hibbits #ifdef __powerpc64__ 475f0bd82a1SJustin Hibbits struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 48); 476f0bd82a1SJustin Hibbits #else 477f0bd82a1SJustin Hibbits struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 8); 478f0bd82a1SJustin Hibbits #endif 479f0bd82a1SJustin Hibbits 480f0bd82a1SJustin Hibbits if (arg <= inreg) { 481f0bd82a1SJustin Hibbits stack = &rp->fixreg[3]; 482f0bd82a1SJustin Hibbits } else { 483f0bd82a1SJustin Hibbits stack = (uintptr_t *)(rp->fixreg[1]); 484f0bd82a1SJustin Hibbits arg -= inreg; 485f0bd82a1SJustin Hibbits } 486f0bd82a1SJustin Hibbits goto load; 487f0bd82a1SJustin Hibbits } 488f0bd82a1SJustin Hibbits 489f0bd82a1SJustin Hibbits } 490f0bd82a1SJustin Hibbits 491f0bd82a1SJustin Hibbits /* 492f0bd82a1SJustin Hibbits * We know that we did not come through a trap to get into 493f0bd82a1SJustin Hibbits * dtrace_probe() -- the provider simply called dtrace_probe() 494f0bd82a1SJustin Hibbits * directly. As this is the case, we need to shift the argument 495f0bd82a1SJustin Hibbits * that we're looking for: the probe ID is the first argument to 496f0bd82a1SJustin Hibbits * dtrace_probe(), so the argument n will actually be found where 497f0bd82a1SJustin Hibbits * one would expect to find argument (n + 1). 498f0bd82a1SJustin Hibbits */ 499f0bd82a1SJustin Hibbits arg++; 500f0bd82a1SJustin Hibbits 501f0bd82a1SJustin Hibbits if (arg <= inreg) { 502f0bd82a1SJustin Hibbits /* 503f0bd82a1SJustin Hibbits * This shouldn't happen. If the argument is passed in a 504f0bd82a1SJustin Hibbits * register then it should have been, well, passed in a 505f0bd82a1SJustin Hibbits * register... 506f0bd82a1SJustin Hibbits */ 507f0bd82a1SJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 508c7570492SJustin Hibbits return (0); 509c7570492SJustin Hibbits } 510c7570492SJustin Hibbits 511f0bd82a1SJustin Hibbits arg -= (inreg + 1); 512f0bd82a1SJustin Hibbits stack = fp + 2; 513c7570492SJustin Hibbits 514f0bd82a1SJustin Hibbits load: 515f0bd82a1SJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); 516f0bd82a1SJustin Hibbits val = stack[arg]; 517f0bd82a1SJustin Hibbits DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); 518c7570492SJustin Hibbits 519f0bd82a1SJustin Hibbits return (val); 520c7570492SJustin Hibbits } 521c7570492SJustin Hibbits 522c7570492SJustin Hibbits int 523c7570492SJustin Hibbits dtrace_getstackdepth(int aframes) 524c7570492SJustin Hibbits { 525c7570492SJustin Hibbits int depth = 0; 526e40a5cd3SJustin Hibbits uintptr_t osp, sp; 527e40a5cd3SJustin Hibbits vm_offset_t callpc; 528c7570492SJustin Hibbits 529e40a5cd3SJustin Hibbits osp = PAGE_SIZE; 530c7570492SJustin Hibbits aframes++; 531c7570492SJustin Hibbits sp = dtrace_getfp(); 532c7570492SJustin Hibbits depth++; 533c7570492SJustin Hibbits for(;;) { 534e40a5cd3SJustin Hibbits if (sp <= osp) 535c7570492SJustin Hibbits break; 536e40a5cd3SJustin Hibbits 537*675cad71SJustin Hibbits if (!dtrace_sp_inkernel(sp)) 538c7570492SJustin Hibbits break; 539e40a5cd3SJustin Hibbits 540e40a5cd3SJustin Hibbits if (aframes == 0) 541c7570492SJustin Hibbits depth++; 542e40a5cd3SJustin Hibbits else 543e40a5cd3SJustin Hibbits aframes--; 544e40a5cd3SJustin Hibbits osp = sp; 545161c4151SJustin Hibbits sp = dtrace_next_sp(sp); 546c7570492SJustin Hibbits } 547c7570492SJustin Hibbits if (depth < aframes) 548e40a5cd3SJustin Hibbits return (0); 549e40a5cd3SJustin Hibbits 550e40a5cd3SJustin Hibbits return (depth); 551c7570492SJustin Hibbits } 552c7570492SJustin Hibbits 553c7570492SJustin Hibbits ulong_t 554c7570492SJustin Hibbits dtrace_getreg(struct trapframe *rp, uint_t reg) 555c7570492SJustin Hibbits { 556c7570492SJustin Hibbits if (reg < 32) 557c7570492SJustin Hibbits return (rp->fixreg[reg]); 558c7570492SJustin Hibbits 559c7570492SJustin Hibbits switch (reg) { 560c7570492SJustin Hibbits case 33: 561c7570492SJustin Hibbits return (rp->lr); 562c7570492SJustin Hibbits case 34: 563c7570492SJustin Hibbits return (rp->cr); 564c7570492SJustin Hibbits case 35: 565c7570492SJustin Hibbits return (rp->xer); 566c7570492SJustin Hibbits case 36: 567c7570492SJustin Hibbits return (rp->ctr); 568c7570492SJustin Hibbits case 37: 569c7570492SJustin Hibbits return (rp->srr0); 570c7570492SJustin Hibbits case 38: 571c7570492SJustin Hibbits return (rp->srr1); 572c7570492SJustin Hibbits case 39: 573c7570492SJustin Hibbits return (rp->exc); 574c7570492SJustin Hibbits default: 575c7570492SJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 576c7570492SJustin Hibbits return (0); 577c7570492SJustin Hibbits } 578c7570492SJustin Hibbits } 579c7570492SJustin Hibbits 580c7570492SJustin Hibbits static int 581c7570492SJustin Hibbits dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) 582c7570492SJustin Hibbits { 583c7570492SJustin Hibbits ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr); 584c7570492SJustin Hibbits 585c7570492SJustin Hibbits if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { 586c7570492SJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 587c7570492SJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = uaddr; 588c7570492SJustin Hibbits return (0); 589c7570492SJustin Hibbits } 590c7570492SJustin Hibbits 591c7570492SJustin Hibbits return (1); 592c7570492SJustin Hibbits } 593c7570492SJustin Hibbits 594c7570492SJustin Hibbits void 595c7570492SJustin Hibbits dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, 596c7570492SJustin Hibbits volatile uint16_t *flags) 597c7570492SJustin Hibbits { 598c7570492SJustin Hibbits if (dtrace_copycheck(uaddr, kaddr, size)) 5997e7a9efdSJustin Hibbits if (copyin((const void *)uaddr, (void *)kaddr, size)) { 6007e7a9efdSJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 6017e7a9efdSJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 6027e7a9efdSJustin Hibbits } 603c7570492SJustin Hibbits } 604c7570492SJustin Hibbits 605c7570492SJustin Hibbits void 606c7570492SJustin Hibbits dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, 607c7570492SJustin Hibbits volatile uint16_t *flags) 608c7570492SJustin Hibbits { 6097e7a9efdSJustin Hibbits if (dtrace_copycheck(uaddr, kaddr, size)) { 6107e7a9efdSJustin Hibbits if (copyout((const void *)kaddr, (void *)uaddr, size)) { 6117e7a9efdSJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 6127e7a9efdSJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 6137e7a9efdSJustin Hibbits } 6147e7a9efdSJustin Hibbits } 615c7570492SJustin Hibbits } 616c7570492SJustin Hibbits 617c7570492SJustin Hibbits void 618c7570492SJustin Hibbits dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, 619c7570492SJustin Hibbits volatile uint16_t *flags) 620c7570492SJustin Hibbits { 6217e7a9efdSJustin Hibbits size_t actual; 6227e7a9efdSJustin Hibbits int error; 6237e7a9efdSJustin Hibbits 6247e7a9efdSJustin Hibbits if (dtrace_copycheck(uaddr, kaddr, size)) { 6257e7a9efdSJustin Hibbits error = copyinstr((const void *)uaddr, (void *)kaddr, 6267e7a9efdSJustin Hibbits size, &actual); 6277e7a9efdSJustin Hibbits 6287e7a9efdSJustin Hibbits /* ENAMETOOLONG is not a fault condition. */ 6297e7a9efdSJustin Hibbits if (error && error != ENAMETOOLONG) { 6307e7a9efdSJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 6317e7a9efdSJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 6327e7a9efdSJustin Hibbits } 6337e7a9efdSJustin Hibbits } 634c7570492SJustin Hibbits } 635c7570492SJustin Hibbits 6367e7a9efdSJustin Hibbits /* 6377e7a9efdSJustin Hibbits * The bulk of this function could be replaced to match dtrace_copyinstr() 6387e7a9efdSJustin Hibbits * if we ever implement a copyoutstr(). 6397e7a9efdSJustin Hibbits */ 640c7570492SJustin Hibbits void 641c7570492SJustin Hibbits dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, 642c7570492SJustin Hibbits volatile uint16_t *flags) 643c7570492SJustin Hibbits { 6447e7a9efdSJustin Hibbits size_t len; 6457e7a9efdSJustin Hibbits 6467e7a9efdSJustin Hibbits if (dtrace_copycheck(uaddr, kaddr, size)) { 6477e7a9efdSJustin Hibbits len = strlen((const char *)kaddr); 6487e7a9efdSJustin Hibbits if (len > size) 6497e7a9efdSJustin Hibbits len = size; 6507e7a9efdSJustin Hibbits 6517e7a9efdSJustin Hibbits if (copyout((const void *)kaddr, (void *)uaddr, len)) { 6527e7a9efdSJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 6537e7a9efdSJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 6547e7a9efdSJustin Hibbits } 6557e7a9efdSJustin Hibbits } 656c7570492SJustin Hibbits } 657c7570492SJustin Hibbits 658c7570492SJustin Hibbits uint8_t 659c7570492SJustin Hibbits dtrace_fuword8(void *uaddr) 660c7570492SJustin Hibbits { 661c7570492SJustin Hibbits if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 662c7570492SJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 663c7570492SJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 664c7570492SJustin Hibbits return (0); 665c7570492SJustin Hibbits } 6667e7a9efdSJustin Hibbits return (fubyte(uaddr)); 667c7570492SJustin Hibbits } 668c7570492SJustin Hibbits 669c7570492SJustin Hibbits uint16_t 670c7570492SJustin Hibbits dtrace_fuword16(void *uaddr) 671c7570492SJustin Hibbits { 6727e7a9efdSJustin Hibbits uint16_t ret = 0; 6737e7a9efdSJustin Hibbits 6747e7a9efdSJustin Hibbits if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) { 6757e7a9efdSJustin Hibbits if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) { 676c7570492SJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 677c7570492SJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 678c7570492SJustin Hibbits } 6797e7a9efdSJustin Hibbits } 6807e7a9efdSJustin Hibbits return ret; 681c7570492SJustin Hibbits } 682c7570492SJustin Hibbits 683c7570492SJustin Hibbits uint32_t 684c7570492SJustin Hibbits dtrace_fuword32(void *uaddr) 685c7570492SJustin Hibbits { 686c7570492SJustin Hibbits if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 687c7570492SJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 688c7570492SJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 689c7570492SJustin Hibbits return (0); 690c7570492SJustin Hibbits } 6917e7a9efdSJustin Hibbits return (fuword32(uaddr)); 692c7570492SJustin Hibbits } 693c7570492SJustin Hibbits 694c7570492SJustin Hibbits uint64_t 695c7570492SJustin Hibbits dtrace_fuword64(void *uaddr) 696c7570492SJustin Hibbits { 6977e7a9efdSJustin Hibbits uint64_t ret = 0; 6987e7a9efdSJustin Hibbits 6997e7a9efdSJustin Hibbits if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) { 7007e7a9efdSJustin Hibbits if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) { 701c7570492SJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 702c7570492SJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 703c7570492SJustin Hibbits } 7047e7a9efdSJustin Hibbits } 7057e7a9efdSJustin Hibbits return ret; 706c7570492SJustin Hibbits } 70780a5635cSJustin Hibbits 70880a5635cSJustin Hibbits uintptr_t 70980a5635cSJustin Hibbits dtrace_fulword(void *uaddr) 71080a5635cSJustin Hibbits { 71180a5635cSJustin Hibbits uintptr_t ret = 0; 71280a5635cSJustin Hibbits 71380a5635cSJustin Hibbits if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) { 71480a5635cSJustin Hibbits if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) { 71580a5635cSJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 71680a5635cSJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 71780a5635cSJustin Hibbits } 71880a5635cSJustin Hibbits } 71980a5635cSJustin Hibbits return ret; 72080a5635cSJustin Hibbits } 721