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> 41c7570492SJustin Hibbits #include <machine/reg.h> 42c7570492SJustin Hibbits #include <machine/stack.h> 43c7570492SJustin Hibbits 44c7570492SJustin Hibbits #include <vm/vm.h> 45c7570492SJustin Hibbits #include <vm/vm_param.h> 46c7570492SJustin Hibbits #include <vm/pmap.h> 47c7570492SJustin Hibbits 48c7570492SJustin Hibbits #include "regset.h" 49c7570492SJustin Hibbits 50c7570492SJustin Hibbits /* Offset to the LR Save word (ppc32) */ 51c7570492SJustin Hibbits #define RETURN_OFFSET 4 52*594ce9adSJustin Hibbits /* Offset to LR Save word (ppc64). CR Save area sits between back chain and LR */ 53*594ce9adSJustin Hibbits #define RETURN_OFFSET64 16 54c7570492SJustin Hibbits 55c7570492SJustin Hibbits #define INKERNEL(x) ((x) <= VM_MAX_KERNEL_ADDRESS && \ 56c7570492SJustin Hibbits (x) >= VM_MIN_KERNEL_ADDRESS) 57c7570492SJustin Hibbits 58c7570492SJustin Hibbits greg_t 59c7570492SJustin Hibbits dtrace_getfp(void) 60c7570492SJustin Hibbits { 61c7570492SJustin Hibbits return (greg_t)__builtin_frame_address(0); 62c7570492SJustin Hibbits } 63c7570492SJustin Hibbits 64c7570492SJustin Hibbits void 65c7570492SJustin Hibbits dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, 66c7570492SJustin Hibbits uint32_t *intrpc) 67c7570492SJustin Hibbits { 68c7570492SJustin Hibbits int depth = 0; 69c7570492SJustin Hibbits register_t sp; 70c7570492SJustin Hibbits vm_offset_t callpc; 71c7570492SJustin Hibbits pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; 72c7570492SJustin Hibbits 73c7570492SJustin Hibbits if (intrpc != 0) 74c7570492SJustin Hibbits pcstack[depth++] = (pc_t) intrpc; 75c7570492SJustin Hibbits 76c7570492SJustin Hibbits aframes++; 77c7570492SJustin Hibbits 78c7570492SJustin Hibbits sp = dtrace_getfp(); 79c7570492SJustin Hibbits 80c7570492SJustin Hibbits while (depth < pcstack_limit) { 81c7570492SJustin Hibbits if (!INKERNEL((long) sp)) 82c7570492SJustin Hibbits break; 83c7570492SJustin Hibbits 84cc117e27SJustin Hibbits #ifdef __powerpc64__ 85cc117e27SJustin Hibbits callpc = *(uintptr_t *)(sp + RETURN_OFFSET64); 86cc117e27SJustin Hibbits #else 87c7570492SJustin Hibbits callpc = *(uintptr_t *)(sp + RETURN_OFFSET); 88cc117e27SJustin Hibbits #endif 89c7570492SJustin Hibbits 90c7570492SJustin Hibbits if (!INKERNEL(callpc)) 91c7570492SJustin Hibbits break; 92c7570492SJustin Hibbits 93c7570492SJustin Hibbits if (aframes > 0) { 94c7570492SJustin Hibbits aframes--; 95c7570492SJustin Hibbits if ((aframes == 0) && (caller != 0)) { 96c7570492SJustin Hibbits pcstack[depth++] = caller; 97c7570492SJustin Hibbits } 98c7570492SJustin Hibbits } 99c7570492SJustin Hibbits else { 100c7570492SJustin Hibbits pcstack[depth++] = callpc; 101c7570492SJustin Hibbits } 102c7570492SJustin Hibbits 103c7570492SJustin Hibbits sp = *(uintptr_t*)sp; 104c7570492SJustin Hibbits } 105c7570492SJustin Hibbits 106c7570492SJustin Hibbits for (; depth < pcstack_limit; depth++) { 107c7570492SJustin Hibbits pcstack[depth] = 0; 108c7570492SJustin Hibbits } 109c7570492SJustin Hibbits } 110c7570492SJustin Hibbits 111c7570492SJustin Hibbits static int 112c7570492SJustin Hibbits dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, 113c7570492SJustin Hibbits uintptr_t sp) 114c7570492SJustin Hibbits { 115c7570492SJustin Hibbits proc_t *p = curproc; 116c7570492SJustin Hibbits int ret = 0; 117c7570492SJustin Hibbits 118c7570492SJustin Hibbits ASSERT(pcstack == NULL || pcstack_limit > 0); 119c7570492SJustin Hibbits 120c7570492SJustin Hibbits while (pc != 0) { 121c7570492SJustin Hibbits ret++; 122c7570492SJustin Hibbits if (pcstack != NULL) { 123c7570492SJustin Hibbits *pcstack++ = (uint64_t)pc; 124c7570492SJustin Hibbits pcstack_limit--; 125c7570492SJustin Hibbits if (pcstack_limit <= 0) 126c7570492SJustin Hibbits break; 127c7570492SJustin Hibbits } 128c7570492SJustin Hibbits 129c7570492SJustin Hibbits if (sp == 0) 130c7570492SJustin Hibbits break; 131c7570492SJustin Hibbits 132c7570492SJustin Hibbits if (SV_PROC_FLAG(p, SV_ILP32)) { 133c7570492SJustin Hibbits pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET)); 134c7570492SJustin Hibbits sp = dtrace_fuword32((void *)sp); 135c7570492SJustin Hibbits } 136c7570492SJustin Hibbits else { 137c7570492SJustin Hibbits pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64)); 138c7570492SJustin Hibbits sp = dtrace_fuword64((void *)sp); 139c7570492SJustin Hibbits } 140c7570492SJustin Hibbits } 141c7570492SJustin Hibbits 142c7570492SJustin Hibbits return (ret); 143c7570492SJustin Hibbits } 144c7570492SJustin Hibbits 145c7570492SJustin Hibbits void 146c7570492SJustin Hibbits dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) 147c7570492SJustin Hibbits { 148c7570492SJustin Hibbits proc_t *p = curproc; 149c7570492SJustin Hibbits struct trapframe *tf; 150c7570492SJustin Hibbits uintptr_t pc, sp; 151c7570492SJustin Hibbits volatile uint16_t *flags = 152c7570492SJustin Hibbits (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 153c7570492SJustin Hibbits int n; 154c7570492SJustin Hibbits 155c7570492SJustin Hibbits if (*flags & CPU_DTRACE_FAULT) 156c7570492SJustin Hibbits return; 157c7570492SJustin Hibbits 158c7570492SJustin Hibbits if (pcstack_limit <= 0) 159c7570492SJustin Hibbits return; 160c7570492SJustin Hibbits 161c7570492SJustin Hibbits /* 162c7570492SJustin Hibbits * If there's no user context we still need to zero the stack. 163c7570492SJustin Hibbits */ 164c7570492SJustin Hibbits if (p == NULL || (tf = curthread->td_frame) == NULL) 165c7570492SJustin Hibbits goto zero; 166c7570492SJustin Hibbits 167c7570492SJustin Hibbits *pcstack++ = (uint64_t)p->p_pid; 168c7570492SJustin Hibbits pcstack_limit--; 169c7570492SJustin Hibbits 170c7570492SJustin Hibbits if (pcstack_limit <= 0) 171c7570492SJustin Hibbits return; 172c7570492SJustin Hibbits 173c7570492SJustin Hibbits pc = tf->srr0; 174c7570492SJustin Hibbits sp = tf->fixreg[1]; 175c7570492SJustin Hibbits 176c7570492SJustin Hibbits if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 177c7570492SJustin Hibbits /* 178c7570492SJustin Hibbits * In an entry probe. The frame pointer has not yet been 179c7570492SJustin Hibbits * pushed (that happens in the function prologue). The 180c7570492SJustin Hibbits * best approach is to add the current pc as a missing top 181c7570492SJustin Hibbits * of stack and back the pc up to the caller, which is stored 182c7570492SJustin Hibbits * at the current stack pointer address since the call 183c7570492SJustin Hibbits * instruction puts it there right before the branch. 184c7570492SJustin Hibbits */ 185c7570492SJustin Hibbits 186c7570492SJustin Hibbits *pcstack++ = (uint64_t)pc; 187c7570492SJustin Hibbits pcstack_limit--; 188c7570492SJustin Hibbits if (pcstack_limit <= 0) 189c7570492SJustin Hibbits return; 190c7570492SJustin Hibbits 191c7570492SJustin Hibbits pc = tf->lr; 192c7570492SJustin Hibbits } 193c7570492SJustin Hibbits 194c7570492SJustin Hibbits n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp); 195c7570492SJustin Hibbits ASSERT(n >= 0); 196c7570492SJustin Hibbits ASSERT(n <= pcstack_limit); 197c7570492SJustin Hibbits 198c7570492SJustin Hibbits pcstack += n; 199c7570492SJustin Hibbits pcstack_limit -= n; 200c7570492SJustin Hibbits 201c7570492SJustin Hibbits zero: 202c7570492SJustin Hibbits while (pcstack_limit-- > 0) 203c7570492SJustin Hibbits *pcstack++ = 0; 204c7570492SJustin Hibbits } 205c7570492SJustin Hibbits 206c7570492SJustin Hibbits int 207c7570492SJustin Hibbits dtrace_getustackdepth(void) 208c7570492SJustin Hibbits { 209c7570492SJustin Hibbits proc_t *p = curproc; 210c7570492SJustin Hibbits struct trapframe *tf; 211c7570492SJustin Hibbits uintptr_t pc, sp; 212c7570492SJustin Hibbits int n = 0; 213c7570492SJustin Hibbits 214c7570492SJustin Hibbits if (p == NULL || (tf = curthread->td_frame) == NULL) 215c7570492SJustin Hibbits return (0); 216c7570492SJustin Hibbits 217c7570492SJustin Hibbits if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) 218c7570492SJustin Hibbits return (-1); 219c7570492SJustin Hibbits 220c7570492SJustin Hibbits pc = tf->srr0; 221c7570492SJustin Hibbits sp = tf->fixreg[1]; 222c7570492SJustin Hibbits 223c7570492SJustin Hibbits if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 224c7570492SJustin Hibbits /* 225c7570492SJustin Hibbits * In an entry probe. The frame pointer has not yet been 226c7570492SJustin Hibbits * pushed (that happens in the function prologue). The 227c7570492SJustin Hibbits * best approach is to add the current pc as a missing top 228c7570492SJustin Hibbits * of stack and back the pc up to the caller, which is stored 229c7570492SJustin Hibbits * at the current stack pointer address since the call 230c7570492SJustin Hibbits * instruction puts it there right before the branch. 231c7570492SJustin Hibbits */ 232c7570492SJustin Hibbits 233c7570492SJustin Hibbits if (SV_PROC_FLAG(p, SV_ILP32)) { 234c7570492SJustin Hibbits pc = dtrace_fuword32((void *) sp); 235c7570492SJustin Hibbits } 236c7570492SJustin Hibbits else 237c7570492SJustin Hibbits pc = dtrace_fuword64((void *) sp); 238c7570492SJustin Hibbits n++; 239c7570492SJustin Hibbits } 240c7570492SJustin Hibbits 241c7570492SJustin Hibbits n += dtrace_getustack_common(NULL, 0, pc, sp); 242c7570492SJustin Hibbits 243c7570492SJustin Hibbits return (n); 244c7570492SJustin Hibbits } 245c7570492SJustin Hibbits 246c7570492SJustin Hibbits void 247c7570492SJustin Hibbits dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) 248c7570492SJustin Hibbits { 249c7570492SJustin Hibbits proc_t *p = curproc; 250c7570492SJustin Hibbits struct trapframe *tf; 251c7570492SJustin Hibbits uintptr_t pc, sp; 252c7570492SJustin Hibbits volatile uint16_t *flags = 253c7570492SJustin Hibbits (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 254c7570492SJustin Hibbits #ifdef notyet /* XXX signal stack */ 255c7570492SJustin Hibbits uintptr_t oldcontext; 256c7570492SJustin Hibbits size_t s1, s2; 257c7570492SJustin Hibbits #endif 258c7570492SJustin Hibbits 259c7570492SJustin Hibbits if (*flags & CPU_DTRACE_FAULT) 260c7570492SJustin Hibbits return; 261c7570492SJustin Hibbits 262c7570492SJustin Hibbits if (pcstack_limit <= 0) 263c7570492SJustin Hibbits return; 264c7570492SJustin Hibbits 265c7570492SJustin Hibbits /* 266c7570492SJustin Hibbits * If there's no user context we still need to zero the stack. 267c7570492SJustin Hibbits */ 268c7570492SJustin Hibbits if (p == NULL || (tf = curthread->td_frame) == NULL) 269c7570492SJustin Hibbits goto zero; 270c7570492SJustin Hibbits 271c7570492SJustin Hibbits *pcstack++ = (uint64_t)p->p_pid; 272c7570492SJustin Hibbits pcstack_limit--; 273c7570492SJustin Hibbits 274c7570492SJustin Hibbits if (pcstack_limit <= 0) 275c7570492SJustin Hibbits return; 276c7570492SJustin Hibbits 277c7570492SJustin Hibbits pc = tf->srr0; 278c7570492SJustin Hibbits sp = tf->fixreg[1]; 279c7570492SJustin Hibbits 280c7570492SJustin Hibbits #ifdef notyet /* XXX signal stack */ 281c7570492SJustin Hibbits oldcontext = lwp->lwp_oldcontext; 282c7570492SJustin Hibbits s1 = sizeof (struct xframe) + 2 * sizeof (long); 283c7570492SJustin Hibbits s2 = s1 + sizeof (siginfo_t); 284c7570492SJustin Hibbits #endif 285c7570492SJustin Hibbits 286c7570492SJustin Hibbits if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 287c7570492SJustin Hibbits *pcstack++ = (uint64_t)pc; 288c7570492SJustin Hibbits *fpstack++ = 0; 289c7570492SJustin Hibbits pcstack_limit--; 290c7570492SJustin Hibbits if (pcstack_limit <= 0) 291c7570492SJustin Hibbits return; 292c7570492SJustin Hibbits 293c7570492SJustin Hibbits if (SV_PROC_FLAG(p, SV_ILP32)) { 294c7570492SJustin Hibbits pc = dtrace_fuword32((void *)sp); 295c7570492SJustin Hibbits } 296c7570492SJustin Hibbits else { 297c7570492SJustin Hibbits pc = dtrace_fuword64((void *)sp); 298c7570492SJustin Hibbits } 299c7570492SJustin Hibbits } 300c7570492SJustin Hibbits 301c7570492SJustin Hibbits while (pc != 0) { 302c7570492SJustin Hibbits *pcstack++ = (uint64_t)pc; 303c7570492SJustin Hibbits *fpstack++ = sp; 304c7570492SJustin Hibbits pcstack_limit--; 305c7570492SJustin Hibbits if (pcstack_limit <= 0) 306c7570492SJustin Hibbits break; 307c7570492SJustin Hibbits 308c7570492SJustin Hibbits if (sp == 0) 309c7570492SJustin Hibbits break; 310c7570492SJustin Hibbits 311c7570492SJustin Hibbits #ifdef notyet /* XXX signal stack */ 312c7570492SJustin Hibbits if (oldcontext == sp + s1 || oldcontext == sp + s2) { 313c7570492SJustin Hibbits ucontext_t *ucp = (ucontext_t *)oldcontext; 314c7570492SJustin Hibbits greg_t *gregs = ucp->uc_mcontext.gregs; 315c7570492SJustin Hibbits 316c7570492SJustin Hibbits sp = dtrace_fulword(&gregs[REG_FP]); 317c7570492SJustin Hibbits pc = dtrace_fulword(&gregs[REG_PC]); 318c7570492SJustin Hibbits 319c7570492SJustin Hibbits oldcontext = dtrace_fulword(&ucp->uc_link); 320c7570492SJustin Hibbits } else 321c7570492SJustin Hibbits #endif /* XXX */ 322c7570492SJustin Hibbits { 323c7570492SJustin Hibbits if (SV_PROC_FLAG(p, SV_ILP32)) { 324c7570492SJustin Hibbits pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET)); 325c7570492SJustin Hibbits sp = dtrace_fuword32((void *)sp); 326c7570492SJustin Hibbits } 327c7570492SJustin Hibbits else { 328c7570492SJustin Hibbits pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64)); 329c7570492SJustin Hibbits sp = dtrace_fuword64((void *)sp); 330c7570492SJustin Hibbits } 331c7570492SJustin Hibbits } 332c7570492SJustin Hibbits 333c7570492SJustin Hibbits /* 334c7570492SJustin Hibbits * This is totally bogus: if we faulted, we're going to clear 335c7570492SJustin Hibbits * the fault and break. This is to deal with the apparently 336c7570492SJustin Hibbits * broken Java stacks on x86. 337c7570492SJustin Hibbits */ 338c7570492SJustin Hibbits if (*flags & CPU_DTRACE_FAULT) { 339c7570492SJustin Hibbits *flags &= ~CPU_DTRACE_FAULT; 340c7570492SJustin Hibbits break; 341c7570492SJustin Hibbits } 342c7570492SJustin Hibbits } 343c7570492SJustin Hibbits 344c7570492SJustin Hibbits zero: 345c7570492SJustin Hibbits while (pcstack_limit-- > 0) 346c7570492SJustin Hibbits *pcstack++ = 0; 347c7570492SJustin Hibbits } 348c7570492SJustin Hibbits 349c7570492SJustin Hibbits /*ARGSUSED*/ 350c7570492SJustin Hibbits uint64_t 351c7570492SJustin Hibbits dtrace_getarg(int arg, int aframes) 352c7570492SJustin Hibbits { 353f0bd82a1SJustin Hibbits uintptr_t val; 354f0bd82a1SJustin Hibbits uintptr_t *fp = (uintptr_t *)dtrace_getfp(); 355f0bd82a1SJustin Hibbits uintptr_t *stack; 356f0bd82a1SJustin Hibbits int i; 357f0bd82a1SJustin Hibbits 358f0bd82a1SJustin Hibbits /* 359f0bd82a1SJustin Hibbits * A total of 8 arguments are passed via registers; any argument with 360f0bd82a1SJustin Hibbits * index of 7 or lower is therefore in a register. 361f0bd82a1SJustin Hibbits */ 362f0bd82a1SJustin Hibbits int inreg = 7; 363f0bd82a1SJustin Hibbits 364f0bd82a1SJustin Hibbits for (i = 1; i <= aframes; i++) { 365f0bd82a1SJustin Hibbits fp = (uintptr_t *)*fp; 366f0bd82a1SJustin Hibbits 367f0bd82a1SJustin Hibbits /* 368f0bd82a1SJustin Hibbits * On ppc32 AIM, and booke, trapexit() is the immediately following 369f0bd82a1SJustin Hibbits * label. On ppc64 AIM trapexit() follows a nop. 370f0bd82a1SJustin Hibbits */ 371f0bd82a1SJustin Hibbits if (((long)(fp[1]) == (long)trapexit) || 372f0bd82a1SJustin Hibbits (((long)(fp[1]) + 4 == (long)trapexit))) { 373f0bd82a1SJustin Hibbits /* 374f0bd82a1SJustin Hibbits * In the case of powerpc, we will use the pointer to the regs 375f0bd82a1SJustin Hibbits * structure that was pushed when we took the trap. To get this 376f0bd82a1SJustin Hibbits * structure, we must increment beyond the frame structure. If the 377f0bd82a1SJustin Hibbits * argument that we're seeking is passed on the stack, we'll pull 378f0bd82a1SJustin Hibbits * the true stack pointer out of the saved registers and decrement 379f0bd82a1SJustin Hibbits * our argument by the number of arguments passed in registers; if 380f0bd82a1SJustin Hibbits * the argument we're seeking is passed in regsiters, we can just 381f0bd82a1SJustin Hibbits * load it directly. 382f0bd82a1SJustin Hibbits */ 383f0bd82a1SJustin Hibbits #ifdef __powerpc64__ 384f0bd82a1SJustin Hibbits struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 48); 385f0bd82a1SJustin Hibbits #else 386f0bd82a1SJustin Hibbits struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 8); 387f0bd82a1SJustin Hibbits #endif 388f0bd82a1SJustin Hibbits 389f0bd82a1SJustin Hibbits if (arg <= inreg) { 390f0bd82a1SJustin Hibbits stack = &rp->fixreg[3]; 391f0bd82a1SJustin Hibbits } else { 392f0bd82a1SJustin Hibbits stack = (uintptr_t *)(rp->fixreg[1]); 393f0bd82a1SJustin Hibbits arg -= inreg; 394f0bd82a1SJustin Hibbits } 395f0bd82a1SJustin Hibbits goto load; 396f0bd82a1SJustin Hibbits } 397f0bd82a1SJustin Hibbits 398f0bd82a1SJustin Hibbits } 399f0bd82a1SJustin Hibbits 400f0bd82a1SJustin Hibbits /* 401f0bd82a1SJustin Hibbits * We know that we did not come through a trap to get into 402f0bd82a1SJustin Hibbits * dtrace_probe() -- the provider simply called dtrace_probe() 403f0bd82a1SJustin Hibbits * directly. As this is the case, we need to shift the argument 404f0bd82a1SJustin Hibbits * that we're looking for: the probe ID is the first argument to 405f0bd82a1SJustin Hibbits * dtrace_probe(), so the argument n will actually be found where 406f0bd82a1SJustin Hibbits * one would expect to find argument (n + 1). 407f0bd82a1SJustin Hibbits */ 408f0bd82a1SJustin Hibbits arg++; 409f0bd82a1SJustin Hibbits 410f0bd82a1SJustin Hibbits if (arg <= inreg) { 411f0bd82a1SJustin Hibbits /* 412f0bd82a1SJustin Hibbits * This shouldn't happen. If the argument is passed in a 413f0bd82a1SJustin Hibbits * register then it should have been, well, passed in a 414f0bd82a1SJustin Hibbits * register... 415f0bd82a1SJustin Hibbits */ 416f0bd82a1SJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 417c7570492SJustin Hibbits return (0); 418c7570492SJustin Hibbits } 419c7570492SJustin Hibbits 420f0bd82a1SJustin Hibbits arg -= (inreg + 1); 421f0bd82a1SJustin Hibbits stack = fp + 2; 422c7570492SJustin Hibbits 423f0bd82a1SJustin Hibbits load: 424f0bd82a1SJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); 425f0bd82a1SJustin Hibbits val = stack[arg]; 426f0bd82a1SJustin Hibbits DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); 427c7570492SJustin Hibbits 428f0bd82a1SJustin Hibbits return (val); 429f0bd82a1SJustin Hibbits return (0); 430c7570492SJustin Hibbits } 431c7570492SJustin Hibbits 432c7570492SJustin Hibbits int 433c7570492SJustin Hibbits dtrace_getstackdepth(int aframes) 434c7570492SJustin Hibbits { 435c7570492SJustin Hibbits int depth = 0; 436c7570492SJustin Hibbits register_t sp; 437c7570492SJustin Hibbits 438c7570492SJustin Hibbits aframes++; 439c7570492SJustin Hibbits sp = dtrace_getfp(); 440c7570492SJustin Hibbits depth++; 441c7570492SJustin Hibbits for(;;) { 442c7570492SJustin Hibbits if (!INKERNEL((long) sp)) 443c7570492SJustin Hibbits break; 444c7570492SJustin Hibbits if (!INKERNEL((long) *(void **)sp)) 445c7570492SJustin Hibbits break; 446c7570492SJustin Hibbits depth++; 447c7570492SJustin Hibbits sp = *(uintptr_t *)sp; 448c7570492SJustin Hibbits } 449c7570492SJustin Hibbits if (depth < aframes) 450c7570492SJustin Hibbits return 0; 451c7570492SJustin Hibbits else 452c7570492SJustin Hibbits return depth - aframes; 453c7570492SJustin Hibbits } 454c7570492SJustin Hibbits 455c7570492SJustin Hibbits ulong_t 456c7570492SJustin Hibbits dtrace_getreg(struct trapframe *rp, uint_t reg) 457c7570492SJustin Hibbits { 458c7570492SJustin Hibbits if (reg < 32) 459c7570492SJustin Hibbits return (rp->fixreg[reg]); 460c7570492SJustin Hibbits 461c7570492SJustin Hibbits switch (reg) { 462c7570492SJustin Hibbits case 33: 463c7570492SJustin Hibbits return (rp->lr); 464c7570492SJustin Hibbits case 34: 465c7570492SJustin Hibbits return (rp->cr); 466c7570492SJustin Hibbits case 35: 467c7570492SJustin Hibbits return (rp->xer); 468c7570492SJustin Hibbits case 36: 469c7570492SJustin Hibbits return (rp->ctr); 470c7570492SJustin Hibbits case 37: 471c7570492SJustin Hibbits return (rp->srr0); 472c7570492SJustin Hibbits case 38: 473c7570492SJustin Hibbits return (rp->srr1); 474c7570492SJustin Hibbits case 39: 475c7570492SJustin Hibbits return (rp->exc); 476c7570492SJustin Hibbits default: 477c7570492SJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 478c7570492SJustin Hibbits return (0); 479c7570492SJustin Hibbits } 480c7570492SJustin Hibbits } 481c7570492SJustin Hibbits 482c7570492SJustin Hibbits static int 483c7570492SJustin Hibbits dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) 484c7570492SJustin Hibbits { 485c7570492SJustin Hibbits ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr); 486c7570492SJustin Hibbits 487c7570492SJustin Hibbits if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { 488c7570492SJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 489c7570492SJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = uaddr; 490c7570492SJustin Hibbits return (0); 491c7570492SJustin Hibbits } 492c7570492SJustin Hibbits 493c7570492SJustin Hibbits return (1); 494c7570492SJustin Hibbits } 495c7570492SJustin Hibbits 496c7570492SJustin Hibbits void 497c7570492SJustin Hibbits dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, 498c7570492SJustin Hibbits volatile uint16_t *flags) 499c7570492SJustin Hibbits { 500c7570492SJustin Hibbits if (dtrace_copycheck(uaddr, kaddr, size)) 5017e7a9efdSJustin Hibbits if (copyin((const void *)uaddr, (void *)kaddr, size)) { 5027e7a9efdSJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 5037e7a9efdSJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 5047e7a9efdSJustin Hibbits } 505c7570492SJustin Hibbits } 506c7570492SJustin Hibbits 507c7570492SJustin Hibbits void 508c7570492SJustin Hibbits dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, 509c7570492SJustin Hibbits volatile uint16_t *flags) 510c7570492SJustin Hibbits { 5117e7a9efdSJustin Hibbits if (dtrace_copycheck(uaddr, kaddr, size)) { 5127e7a9efdSJustin Hibbits if (copyout((const void *)kaddr, (void *)uaddr, size)) { 5137e7a9efdSJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 5147e7a9efdSJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 5157e7a9efdSJustin Hibbits } 5167e7a9efdSJustin Hibbits } 517c7570492SJustin Hibbits } 518c7570492SJustin Hibbits 519c7570492SJustin Hibbits void 520c7570492SJustin Hibbits dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, 521c7570492SJustin Hibbits volatile uint16_t *flags) 522c7570492SJustin Hibbits { 5237e7a9efdSJustin Hibbits size_t actual; 5247e7a9efdSJustin Hibbits int error; 5257e7a9efdSJustin Hibbits 5267e7a9efdSJustin Hibbits if (dtrace_copycheck(uaddr, kaddr, size)) { 5277e7a9efdSJustin Hibbits error = copyinstr((const void *)uaddr, (void *)kaddr, 5287e7a9efdSJustin Hibbits size, &actual); 5297e7a9efdSJustin Hibbits 5307e7a9efdSJustin Hibbits /* ENAMETOOLONG is not a fault condition. */ 5317e7a9efdSJustin Hibbits if (error && error != ENAMETOOLONG) { 5327e7a9efdSJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 5337e7a9efdSJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 5347e7a9efdSJustin Hibbits } 5357e7a9efdSJustin Hibbits } 536c7570492SJustin Hibbits } 537c7570492SJustin Hibbits 5387e7a9efdSJustin Hibbits /* 5397e7a9efdSJustin Hibbits * The bulk of this function could be replaced to match dtrace_copyinstr() 5407e7a9efdSJustin Hibbits * if we ever implement a copyoutstr(). 5417e7a9efdSJustin Hibbits */ 542c7570492SJustin Hibbits void 543c7570492SJustin Hibbits dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, 544c7570492SJustin Hibbits volatile uint16_t *flags) 545c7570492SJustin Hibbits { 5467e7a9efdSJustin Hibbits size_t len; 5477e7a9efdSJustin Hibbits 5487e7a9efdSJustin Hibbits if (dtrace_copycheck(uaddr, kaddr, size)) { 5497e7a9efdSJustin Hibbits len = strlen((const char *)kaddr); 5507e7a9efdSJustin Hibbits if (len > size) 5517e7a9efdSJustin Hibbits len = size; 5527e7a9efdSJustin Hibbits 5537e7a9efdSJustin Hibbits if (copyout((const void *)kaddr, (void *)uaddr, len)) { 5547e7a9efdSJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 5557e7a9efdSJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 5567e7a9efdSJustin Hibbits } 5577e7a9efdSJustin Hibbits } 558c7570492SJustin Hibbits } 559c7570492SJustin Hibbits 560c7570492SJustin Hibbits uint8_t 561c7570492SJustin Hibbits dtrace_fuword8(void *uaddr) 562c7570492SJustin Hibbits { 563c7570492SJustin Hibbits if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 564c7570492SJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 565c7570492SJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 566c7570492SJustin Hibbits return (0); 567c7570492SJustin Hibbits } 5687e7a9efdSJustin Hibbits return (fubyte(uaddr)); 569c7570492SJustin Hibbits } 570c7570492SJustin Hibbits 571c7570492SJustin Hibbits uint16_t 572c7570492SJustin Hibbits dtrace_fuword16(void *uaddr) 573c7570492SJustin Hibbits { 5747e7a9efdSJustin Hibbits uint16_t ret = 0; 5757e7a9efdSJustin Hibbits 5767e7a9efdSJustin Hibbits if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) { 5777e7a9efdSJustin Hibbits if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) { 578c7570492SJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 579c7570492SJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 580c7570492SJustin Hibbits } 5817e7a9efdSJustin Hibbits } 5827e7a9efdSJustin Hibbits return ret; 583c7570492SJustin Hibbits } 584c7570492SJustin Hibbits 585c7570492SJustin Hibbits uint32_t 586c7570492SJustin Hibbits dtrace_fuword32(void *uaddr) 587c7570492SJustin Hibbits { 588c7570492SJustin Hibbits if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 589c7570492SJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 590c7570492SJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 591c7570492SJustin Hibbits return (0); 592c7570492SJustin Hibbits } 5937e7a9efdSJustin Hibbits return (fuword32(uaddr)); 594c7570492SJustin Hibbits } 595c7570492SJustin Hibbits 596c7570492SJustin Hibbits uint64_t 597c7570492SJustin Hibbits dtrace_fuword64(void *uaddr) 598c7570492SJustin Hibbits { 5997e7a9efdSJustin Hibbits uint64_t ret = 0; 6007e7a9efdSJustin Hibbits 6017e7a9efdSJustin Hibbits if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) { 6027e7a9efdSJustin Hibbits if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) { 603c7570492SJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 604c7570492SJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 605c7570492SJustin Hibbits } 6067e7a9efdSJustin Hibbits } 6077e7a9efdSJustin Hibbits return ret; 608c7570492SJustin Hibbits } 60980a5635cSJustin Hibbits 61080a5635cSJustin Hibbits uintptr_t 61180a5635cSJustin Hibbits dtrace_fulword(void *uaddr) 61280a5635cSJustin Hibbits { 61380a5635cSJustin Hibbits uintptr_t ret = 0; 61480a5635cSJustin Hibbits 61580a5635cSJustin Hibbits if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) { 61680a5635cSJustin Hibbits if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) { 61780a5635cSJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 61880a5635cSJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 61980a5635cSJustin Hibbits } 62080a5635cSJustin Hibbits } 62180a5635cSJustin Hibbits return ret; 62280a5635cSJustin Hibbits } 623