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 52c7570492SJustin Hibbits #define RETURN_OFFSET64 8 53c7570492SJustin Hibbits 54c7570492SJustin Hibbits #define INKERNEL(x) ((x) <= VM_MAX_KERNEL_ADDRESS && \ 55c7570492SJustin Hibbits (x) >= VM_MIN_KERNEL_ADDRESS) 56c7570492SJustin Hibbits 57c7570492SJustin Hibbits greg_t 58c7570492SJustin Hibbits dtrace_getfp(void) 59c7570492SJustin Hibbits { 60c7570492SJustin Hibbits return (greg_t)__builtin_frame_address(0); 61c7570492SJustin Hibbits } 62c7570492SJustin Hibbits 63c7570492SJustin Hibbits void 64c7570492SJustin Hibbits dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, 65c7570492SJustin Hibbits uint32_t *intrpc) 66c7570492SJustin Hibbits { 67c7570492SJustin Hibbits int depth = 0; 68c7570492SJustin Hibbits register_t sp; 69c7570492SJustin Hibbits vm_offset_t callpc; 70c7570492SJustin Hibbits pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; 71c7570492SJustin Hibbits 72c7570492SJustin Hibbits if (intrpc != 0) 73c7570492SJustin Hibbits pcstack[depth++] = (pc_t) intrpc; 74c7570492SJustin Hibbits 75c7570492SJustin Hibbits aframes++; 76c7570492SJustin Hibbits 77c7570492SJustin Hibbits sp = dtrace_getfp(); 78c7570492SJustin Hibbits 79c7570492SJustin Hibbits while (depth < pcstack_limit) { 80c7570492SJustin Hibbits if (!INKERNEL((long) sp)) 81c7570492SJustin Hibbits break; 82c7570492SJustin Hibbits 83c7570492SJustin Hibbits callpc = *(uintptr_t *)(sp + RETURN_OFFSET); 84c7570492SJustin Hibbits 85c7570492SJustin Hibbits if (!INKERNEL(callpc)) 86c7570492SJustin Hibbits break; 87c7570492SJustin Hibbits 88c7570492SJustin Hibbits if (aframes > 0) { 89c7570492SJustin Hibbits aframes--; 90c7570492SJustin Hibbits if ((aframes == 0) && (caller != 0)) { 91c7570492SJustin Hibbits pcstack[depth++] = caller; 92c7570492SJustin Hibbits } 93c7570492SJustin Hibbits } 94c7570492SJustin Hibbits else { 95c7570492SJustin Hibbits pcstack[depth++] = callpc; 96c7570492SJustin Hibbits } 97c7570492SJustin Hibbits 98c7570492SJustin Hibbits sp = *(uintptr_t*)sp; 99c7570492SJustin Hibbits } 100c7570492SJustin Hibbits 101c7570492SJustin Hibbits for (; depth < pcstack_limit; depth++) { 102c7570492SJustin Hibbits pcstack[depth] = 0; 103c7570492SJustin Hibbits } 104c7570492SJustin Hibbits } 105c7570492SJustin Hibbits 106c7570492SJustin Hibbits static int 107c7570492SJustin Hibbits dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, 108c7570492SJustin Hibbits uintptr_t sp) 109c7570492SJustin Hibbits { 110c7570492SJustin Hibbits proc_t *p = curproc; 111c7570492SJustin Hibbits int ret = 0; 112c7570492SJustin Hibbits 113c7570492SJustin Hibbits ASSERT(pcstack == NULL || pcstack_limit > 0); 114c7570492SJustin Hibbits 115c7570492SJustin Hibbits while (pc != 0) { 116c7570492SJustin Hibbits ret++; 117c7570492SJustin Hibbits if (pcstack != NULL) { 118c7570492SJustin Hibbits *pcstack++ = (uint64_t)pc; 119c7570492SJustin Hibbits pcstack_limit--; 120c7570492SJustin Hibbits if (pcstack_limit <= 0) 121c7570492SJustin Hibbits break; 122c7570492SJustin Hibbits } 123c7570492SJustin Hibbits 124c7570492SJustin Hibbits if (sp == 0) 125c7570492SJustin Hibbits break; 126c7570492SJustin Hibbits 127c7570492SJustin Hibbits if (SV_PROC_FLAG(p, SV_ILP32)) { 128c7570492SJustin Hibbits pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET)); 129c7570492SJustin Hibbits sp = dtrace_fuword32((void *)sp); 130c7570492SJustin Hibbits } 131c7570492SJustin Hibbits else { 132c7570492SJustin Hibbits pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64)); 133c7570492SJustin Hibbits sp = dtrace_fuword64((void *)sp); 134c7570492SJustin Hibbits } 135c7570492SJustin Hibbits } 136c7570492SJustin Hibbits 137c7570492SJustin Hibbits return (ret); 138c7570492SJustin Hibbits } 139c7570492SJustin Hibbits 140c7570492SJustin Hibbits void 141c7570492SJustin Hibbits dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) 142c7570492SJustin Hibbits { 143c7570492SJustin Hibbits proc_t *p = curproc; 144c7570492SJustin Hibbits struct trapframe *tf; 145c7570492SJustin Hibbits uintptr_t pc, sp; 146c7570492SJustin Hibbits volatile uint16_t *flags = 147c7570492SJustin Hibbits (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 148c7570492SJustin Hibbits int n; 149c7570492SJustin Hibbits 150c7570492SJustin Hibbits if (*flags & CPU_DTRACE_FAULT) 151c7570492SJustin Hibbits return; 152c7570492SJustin Hibbits 153c7570492SJustin Hibbits if (pcstack_limit <= 0) 154c7570492SJustin Hibbits return; 155c7570492SJustin Hibbits 156c7570492SJustin Hibbits /* 157c7570492SJustin Hibbits * If there's no user context we still need to zero the stack. 158c7570492SJustin Hibbits */ 159c7570492SJustin Hibbits if (p == NULL || (tf = curthread->td_frame) == NULL) 160c7570492SJustin Hibbits goto zero; 161c7570492SJustin Hibbits 162c7570492SJustin Hibbits *pcstack++ = (uint64_t)p->p_pid; 163c7570492SJustin Hibbits pcstack_limit--; 164c7570492SJustin Hibbits 165c7570492SJustin Hibbits if (pcstack_limit <= 0) 166c7570492SJustin Hibbits return; 167c7570492SJustin Hibbits 168c7570492SJustin Hibbits pc = tf->srr0; 169c7570492SJustin Hibbits sp = tf->fixreg[1]; 170c7570492SJustin Hibbits 171c7570492SJustin Hibbits if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 172c7570492SJustin Hibbits /* 173c7570492SJustin Hibbits * In an entry probe. The frame pointer has not yet been 174c7570492SJustin Hibbits * pushed (that happens in the function prologue). The 175c7570492SJustin Hibbits * best approach is to add the current pc as a missing top 176c7570492SJustin Hibbits * of stack and back the pc up to the caller, which is stored 177c7570492SJustin Hibbits * at the current stack pointer address since the call 178c7570492SJustin Hibbits * instruction puts it there right before the branch. 179c7570492SJustin Hibbits */ 180c7570492SJustin Hibbits 181c7570492SJustin Hibbits *pcstack++ = (uint64_t)pc; 182c7570492SJustin Hibbits pcstack_limit--; 183c7570492SJustin Hibbits if (pcstack_limit <= 0) 184c7570492SJustin Hibbits return; 185c7570492SJustin Hibbits 186c7570492SJustin Hibbits pc = tf->lr; 187c7570492SJustin Hibbits } 188c7570492SJustin Hibbits 189c7570492SJustin Hibbits n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp); 190c7570492SJustin Hibbits ASSERT(n >= 0); 191c7570492SJustin Hibbits ASSERT(n <= pcstack_limit); 192c7570492SJustin Hibbits 193c7570492SJustin Hibbits pcstack += n; 194c7570492SJustin Hibbits pcstack_limit -= n; 195c7570492SJustin Hibbits 196c7570492SJustin Hibbits zero: 197c7570492SJustin Hibbits while (pcstack_limit-- > 0) 198c7570492SJustin Hibbits *pcstack++ = 0; 199c7570492SJustin Hibbits } 200c7570492SJustin Hibbits 201c7570492SJustin Hibbits int 202c7570492SJustin Hibbits dtrace_getustackdepth(void) 203c7570492SJustin Hibbits { 204c7570492SJustin Hibbits proc_t *p = curproc; 205c7570492SJustin Hibbits struct trapframe *tf; 206c7570492SJustin Hibbits uintptr_t pc, sp; 207c7570492SJustin Hibbits int n = 0; 208c7570492SJustin Hibbits 209c7570492SJustin Hibbits if (p == NULL || (tf = curthread->td_frame) == NULL) 210c7570492SJustin Hibbits return (0); 211c7570492SJustin Hibbits 212c7570492SJustin Hibbits if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) 213c7570492SJustin Hibbits return (-1); 214c7570492SJustin Hibbits 215c7570492SJustin Hibbits pc = tf->srr0; 216c7570492SJustin Hibbits sp = tf->fixreg[1]; 217c7570492SJustin Hibbits 218c7570492SJustin Hibbits if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 219c7570492SJustin Hibbits /* 220c7570492SJustin Hibbits * In an entry probe. The frame pointer has not yet been 221c7570492SJustin Hibbits * pushed (that happens in the function prologue). The 222c7570492SJustin Hibbits * best approach is to add the current pc as a missing top 223c7570492SJustin Hibbits * of stack and back the pc up to the caller, which is stored 224c7570492SJustin Hibbits * at the current stack pointer address since the call 225c7570492SJustin Hibbits * instruction puts it there right before the branch. 226c7570492SJustin Hibbits */ 227c7570492SJustin Hibbits 228c7570492SJustin Hibbits if (SV_PROC_FLAG(p, SV_ILP32)) { 229c7570492SJustin Hibbits pc = dtrace_fuword32((void *) sp); 230c7570492SJustin Hibbits } 231c7570492SJustin Hibbits else 232c7570492SJustin Hibbits pc = dtrace_fuword64((void *) sp); 233c7570492SJustin Hibbits n++; 234c7570492SJustin Hibbits } 235c7570492SJustin Hibbits 236c7570492SJustin Hibbits n += dtrace_getustack_common(NULL, 0, pc, sp); 237c7570492SJustin Hibbits 238c7570492SJustin Hibbits return (n); 239c7570492SJustin Hibbits } 240c7570492SJustin Hibbits 241c7570492SJustin Hibbits void 242c7570492SJustin Hibbits dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) 243c7570492SJustin Hibbits { 244c7570492SJustin Hibbits proc_t *p = curproc; 245c7570492SJustin Hibbits struct trapframe *tf; 246c7570492SJustin Hibbits uintptr_t pc, sp; 247c7570492SJustin Hibbits volatile uint16_t *flags = 248c7570492SJustin Hibbits (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 249c7570492SJustin Hibbits #ifdef notyet /* XXX signal stack */ 250c7570492SJustin Hibbits uintptr_t oldcontext; 251c7570492SJustin Hibbits size_t s1, s2; 252c7570492SJustin Hibbits #endif 253c7570492SJustin Hibbits 254c7570492SJustin Hibbits if (*flags & CPU_DTRACE_FAULT) 255c7570492SJustin Hibbits return; 256c7570492SJustin Hibbits 257c7570492SJustin Hibbits if (pcstack_limit <= 0) 258c7570492SJustin Hibbits return; 259c7570492SJustin Hibbits 260c7570492SJustin Hibbits /* 261c7570492SJustin Hibbits * If there's no user context we still need to zero the stack. 262c7570492SJustin Hibbits */ 263c7570492SJustin Hibbits if (p == NULL || (tf = curthread->td_frame) == NULL) 264c7570492SJustin Hibbits goto zero; 265c7570492SJustin Hibbits 266c7570492SJustin Hibbits *pcstack++ = (uint64_t)p->p_pid; 267c7570492SJustin Hibbits pcstack_limit--; 268c7570492SJustin Hibbits 269c7570492SJustin Hibbits if (pcstack_limit <= 0) 270c7570492SJustin Hibbits return; 271c7570492SJustin Hibbits 272c7570492SJustin Hibbits pc = tf->srr0; 273c7570492SJustin Hibbits sp = tf->fixreg[1]; 274c7570492SJustin Hibbits 275c7570492SJustin Hibbits #ifdef notyet /* XXX signal stack */ 276c7570492SJustin Hibbits oldcontext = lwp->lwp_oldcontext; 277c7570492SJustin Hibbits s1 = sizeof (struct xframe) + 2 * sizeof (long); 278c7570492SJustin Hibbits s2 = s1 + sizeof (siginfo_t); 279c7570492SJustin Hibbits #endif 280c7570492SJustin Hibbits 281c7570492SJustin Hibbits if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 282c7570492SJustin Hibbits *pcstack++ = (uint64_t)pc; 283c7570492SJustin Hibbits *fpstack++ = 0; 284c7570492SJustin Hibbits pcstack_limit--; 285c7570492SJustin Hibbits if (pcstack_limit <= 0) 286c7570492SJustin Hibbits return; 287c7570492SJustin Hibbits 288c7570492SJustin Hibbits if (SV_PROC_FLAG(p, SV_ILP32)) { 289c7570492SJustin Hibbits pc = dtrace_fuword32((void *)sp); 290c7570492SJustin Hibbits } 291c7570492SJustin Hibbits else { 292c7570492SJustin Hibbits pc = dtrace_fuword64((void *)sp); 293c7570492SJustin Hibbits } 294c7570492SJustin Hibbits } 295c7570492SJustin Hibbits 296c7570492SJustin Hibbits while (pc != 0) { 297c7570492SJustin Hibbits *pcstack++ = (uint64_t)pc; 298c7570492SJustin Hibbits *fpstack++ = sp; 299c7570492SJustin Hibbits pcstack_limit--; 300c7570492SJustin Hibbits if (pcstack_limit <= 0) 301c7570492SJustin Hibbits break; 302c7570492SJustin Hibbits 303c7570492SJustin Hibbits if (sp == 0) 304c7570492SJustin Hibbits break; 305c7570492SJustin Hibbits 306c7570492SJustin Hibbits #ifdef notyet /* XXX signal stack */ 307c7570492SJustin Hibbits if (oldcontext == sp + s1 || oldcontext == sp + s2) { 308c7570492SJustin Hibbits ucontext_t *ucp = (ucontext_t *)oldcontext; 309c7570492SJustin Hibbits greg_t *gregs = ucp->uc_mcontext.gregs; 310c7570492SJustin Hibbits 311c7570492SJustin Hibbits sp = dtrace_fulword(&gregs[REG_FP]); 312c7570492SJustin Hibbits pc = dtrace_fulword(&gregs[REG_PC]); 313c7570492SJustin Hibbits 314c7570492SJustin Hibbits oldcontext = dtrace_fulword(&ucp->uc_link); 315c7570492SJustin Hibbits } else 316c7570492SJustin Hibbits #endif /* XXX */ 317c7570492SJustin Hibbits { 318c7570492SJustin Hibbits if (SV_PROC_FLAG(p, SV_ILP32)) { 319c7570492SJustin Hibbits pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET)); 320c7570492SJustin Hibbits sp = dtrace_fuword32((void *)sp); 321c7570492SJustin Hibbits } 322c7570492SJustin Hibbits else { 323c7570492SJustin Hibbits pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64)); 324c7570492SJustin Hibbits sp = dtrace_fuword64((void *)sp); 325c7570492SJustin Hibbits } 326c7570492SJustin Hibbits } 327c7570492SJustin Hibbits 328c7570492SJustin Hibbits /* 329c7570492SJustin Hibbits * This is totally bogus: if we faulted, we're going to clear 330c7570492SJustin Hibbits * the fault and break. This is to deal with the apparently 331c7570492SJustin Hibbits * broken Java stacks on x86. 332c7570492SJustin Hibbits */ 333c7570492SJustin Hibbits if (*flags & CPU_DTRACE_FAULT) { 334c7570492SJustin Hibbits *flags &= ~CPU_DTRACE_FAULT; 335c7570492SJustin Hibbits break; 336c7570492SJustin Hibbits } 337c7570492SJustin Hibbits } 338c7570492SJustin Hibbits 339c7570492SJustin Hibbits zero: 340c7570492SJustin Hibbits while (pcstack_limit-- > 0) 341c7570492SJustin Hibbits *pcstack++ = 0; 342c7570492SJustin Hibbits } 343c7570492SJustin Hibbits 344c7570492SJustin Hibbits /*ARGSUSED*/ 345c7570492SJustin Hibbits uint64_t 346c7570492SJustin Hibbits dtrace_getarg(int arg, int aframes) 347c7570492SJustin Hibbits { 348c7570492SJustin Hibbits return (0); 349c7570492SJustin Hibbits } 350c7570492SJustin Hibbits 351c7570492SJustin Hibbits #ifdef notyet 352c7570492SJustin Hibbits { 353c7570492SJustin Hibbits int depth = 0; 354c7570492SJustin Hibbits register_t sp; 355c7570492SJustin Hibbits vm_offset_t callpc; 356c7570492SJustin Hibbits pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; 357c7570492SJustin Hibbits 358c7570492SJustin Hibbits if (intrpc != 0) 359c7570492SJustin Hibbits pcstack[depth++] = (pc_t) intrpc; 360c7570492SJustin Hibbits 361c7570492SJustin Hibbits aframes++; 362c7570492SJustin Hibbits 363c7570492SJustin Hibbits sp = dtrace_getfp(); 364c7570492SJustin Hibbits 365c7570492SJustin Hibbits while (depth < pcstack_limit) { 366c7570492SJustin Hibbits if (!INKERNEL((long) frame)) 367c7570492SJustin Hibbits break; 368c7570492SJustin Hibbits 369c7570492SJustin Hibbits callpc = *(void **)(sp + RETURN_OFFSET); 370c7570492SJustin Hibbits 371c7570492SJustin Hibbits if (!INKERNEL(callpc)) 372c7570492SJustin Hibbits break; 373c7570492SJustin Hibbits 374c7570492SJustin Hibbits if (aframes > 0) { 375c7570492SJustin Hibbits aframes--; 376c7570492SJustin Hibbits if ((aframes == 0) && (caller != 0)) { 377c7570492SJustin Hibbits pcstack[depth++] = caller; 378c7570492SJustin Hibbits } 379c7570492SJustin Hibbits } 380c7570492SJustin Hibbits else { 381c7570492SJustin Hibbits pcstack[depth++] = callpc; 382c7570492SJustin Hibbits } 383c7570492SJustin Hibbits 384c7570492SJustin Hibbits sp = *(void **)sp; 385c7570492SJustin Hibbits } 386c7570492SJustin Hibbits 387c7570492SJustin Hibbits for (; depth < pcstack_limit; depth++) { 388c7570492SJustin Hibbits pcstack[depth] = 0; 389c7570492SJustin Hibbits } 390c7570492SJustin Hibbits } 391c7570492SJustin Hibbits #endif 392c7570492SJustin Hibbits 393c7570492SJustin Hibbits int 394c7570492SJustin Hibbits dtrace_getstackdepth(int aframes) 395c7570492SJustin Hibbits { 396c7570492SJustin Hibbits int depth = 0; 397c7570492SJustin Hibbits register_t sp; 398c7570492SJustin Hibbits 399c7570492SJustin Hibbits aframes++; 400c7570492SJustin Hibbits sp = dtrace_getfp(); 401c7570492SJustin Hibbits depth++; 402c7570492SJustin Hibbits for(;;) { 403c7570492SJustin Hibbits if (!INKERNEL((long) sp)) 404c7570492SJustin Hibbits break; 405c7570492SJustin Hibbits if (!INKERNEL((long) *(void **)sp)) 406c7570492SJustin Hibbits break; 407c7570492SJustin Hibbits depth++; 408c7570492SJustin Hibbits sp = *(uintptr_t *)sp; 409c7570492SJustin Hibbits } 410c7570492SJustin Hibbits if (depth < aframes) 411c7570492SJustin Hibbits return 0; 412c7570492SJustin Hibbits else 413c7570492SJustin Hibbits return depth - aframes; 414c7570492SJustin Hibbits } 415c7570492SJustin Hibbits 416c7570492SJustin Hibbits ulong_t 417c7570492SJustin Hibbits dtrace_getreg(struct trapframe *rp, uint_t reg) 418c7570492SJustin Hibbits { 419c7570492SJustin Hibbits if (reg < 32) 420c7570492SJustin Hibbits return (rp->fixreg[reg]); 421c7570492SJustin Hibbits 422c7570492SJustin Hibbits switch (reg) { 423c7570492SJustin Hibbits case 33: 424c7570492SJustin Hibbits return (rp->lr); 425c7570492SJustin Hibbits case 34: 426c7570492SJustin Hibbits return (rp->cr); 427c7570492SJustin Hibbits case 35: 428c7570492SJustin Hibbits return (rp->xer); 429c7570492SJustin Hibbits case 36: 430c7570492SJustin Hibbits return (rp->ctr); 431c7570492SJustin Hibbits case 37: 432c7570492SJustin Hibbits return (rp->srr0); 433c7570492SJustin Hibbits case 38: 434c7570492SJustin Hibbits return (rp->srr1); 435c7570492SJustin Hibbits case 39: 436c7570492SJustin Hibbits return (rp->exc); 437c7570492SJustin Hibbits default: 438c7570492SJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 439c7570492SJustin Hibbits return (0); 440c7570492SJustin Hibbits } 441c7570492SJustin Hibbits } 442c7570492SJustin Hibbits 443c7570492SJustin Hibbits static int 444c7570492SJustin Hibbits dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) 445c7570492SJustin Hibbits { 446c7570492SJustin Hibbits ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr); 447c7570492SJustin Hibbits 448c7570492SJustin Hibbits if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { 449c7570492SJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 450c7570492SJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = uaddr; 451c7570492SJustin Hibbits return (0); 452c7570492SJustin Hibbits } 453c7570492SJustin Hibbits 454c7570492SJustin Hibbits return (1); 455c7570492SJustin Hibbits } 456c7570492SJustin Hibbits 457c7570492SJustin Hibbits void 458c7570492SJustin Hibbits dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, 459c7570492SJustin Hibbits volatile uint16_t *flags) 460c7570492SJustin Hibbits { 461c7570492SJustin Hibbits if (dtrace_copycheck(uaddr, kaddr, size)) 4627e7a9efdSJustin Hibbits if (copyin((const void *)uaddr, (void *)kaddr, size)) { 4637e7a9efdSJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 4647e7a9efdSJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 4657e7a9efdSJustin Hibbits } 466c7570492SJustin Hibbits } 467c7570492SJustin Hibbits 468c7570492SJustin Hibbits void 469c7570492SJustin Hibbits dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, 470c7570492SJustin Hibbits volatile uint16_t *flags) 471c7570492SJustin Hibbits { 4727e7a9efdSJustin Hibbits if (dtrace_copycheck(uaddr, kaddr, size)) { 4737e7a9efdSJustin Hibbits if (copyout((const void *)kaddr, (void *)uaddr, size)) { 4747e7a9efdSJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 4757e7a9efdSJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 4767e7a9efdSJustin Hibbits } 4777e7a9efdSJustin Hibbits } 478c7570492SJustin Hibbits } 479c7570492SJustin Hibbits 480c7570492SJustin Hibbits void 481c7570492SJustin Hibbits dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, 482c7570492SJustin Hibbits volatile uint16_t *flags) 483c7570492SJustin Hibbits { 4847e7a9efdSJustin Hibbits size_t actual; 4857e7a9efdSJustin Hibbits int error; 4867e7a9efdSJustin Hibbits 4877e7a9efdSJustin Hibbits if (dtrace_copycheck(uaddr, kaddr, size)) { 4887e7a9efdSJustin Hibbits error = copyinstr((const void *)uaddr, (void *)kaddr, 4897e7a9efdSJustin Hibbits size, &actual); 4907e7a9efdSJustin Hibbits 4917e7a9efdSJustin Hibbits /* ENAMETOOLONG is not a fault condition. */ 4927e7a9efdSJustin Hibbits if (error && error != ENAMETOOLONG) { 4937e7a9efdSJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 4947e7a9efdSJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 4957e7a9efdSJustin Hibbits } 4967e7a9efdSJustin Hibbits } 497c7570492SJustin Hibbits } 498c7570492SJustin Hibbits 4997e7a9efdSJustin Hibbits /* 5007e7a9efdSJustin Hibbits * The bulk of this function could be replaced to match dtrace_copyinstr() 5017e7a9efdSJustin Hibbits * if we ever implement a copyoutstr(). 5027e7a9efdSJustin Hibbits */ 503c7570492SJustin Hibbits void 504c7570492SJustin Hibbits dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, 505c7570492SJustin Hibbits volatile uint16_t *flags) 506c7570492SJustin Hibbits { 5077e7a9efdSJustin Hibbits size_t len; 5087e7a9efdSJustin Hibbits 5097e7a9efdSJustin Hibbits if (dtrace_copycheck(uaddr, kaddr, size)) { 5107e7a9efdSJustin Hibbits len = strlen((const char *)kaddr); 5117e7a9efdSJustin Hibbits if (len > size) 5127e7a9efdSJustin Hibbits len = size; 5137e7a9efdSJustin Hibbits 5147e7a9efdSJustin Hibbits if (copyout((const void *)kaddr, (void *)uaddr, len)) { 5157e7a9efdSJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 5167e7a9efdSJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 5177e7a9efdSJustin Hibbits } 5187e7a9efdSJustin Hibbits } 519c7570492SJustin Hibbits } 520c7570492SJustin Hibbits 521c7570492SJustin Hibbits uint8_t 522c7570492SJustin Hibbits dtrace_fuword8(void *uaddr) 523c7570492SJustin Hibbits { 524c7570492SJustin Hibbits if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 525c7570492SJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 526c7570492SJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 527c7570492SJustin Hibbits return (0); 528c7570492SJustin Hibbits } 5297e7a9efdSJustin Hibbits return (fubyte(uaddr)); 530c7570492SJustin Hibbits } 531c7570492SJustin Hibbits 532c7570492SJustin Hibbits uint16_t 533c7570492SJustin Hibbits dtrace_fuword16(void *uaddr) 534c7570492SJustin Hibbits { 5357e7a9efdSJustin Hibbits uint16_t ret = 0; 5367e7a9efdSJustin Hibbits 5377e7a9efdSJustin Hibbits if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) { 5387e7a9efdSJustin Hibbits if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) { 539c7570492SJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 540c7570492SJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 541c7570492SJustin Hibbits } 5427e7a9efdSJustin Hibbits } 5437e7a9efdSJustin Hibbits return ret; 544c7570492SJustin Hibbits } 545c7570492SJustin Hibbits 546c7570492SJustin Hibbits uint32_t 547c7570492SJustin Hibbits dtrace_fuword32(void *uaddr) 548c7570492SJustin Hibbits { 549c7570492SJustin Hibbits if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 550c7570492SJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 551c7570492SJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 552c7570492SJustin Hibbits return (0); 553c7570492SJustin Hibbits } 5547e7a9efdSJustin Hibbits return (fuword32(uaddr)); 555c7570492SJustin Hibbits } 556c7570492SJustin Hibbits 557c7570492SJustin Hibbits uint64_t 558c7570492SJustin Hibbits dtrace_fuword64(void *uaddr) 559c7570492SJustin Hibbits { 5607e7a9efdSJustin Hibbits uint64_t ret = 0; 5617e7a9efdSJustin Hibbits 5627e7a9efdSJustin Hibbits if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) { 5637e7a9efdSJustin Hibbits if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) { 564c7570492SJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 565c7570492SJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 566c7570492SJustin Hibbits } 5677e7a9efdSJustin Hibbits } 5687e7a9efdSJustin Hibbits return ret; 569c7570492SJustin Hibbits } 570*80a5635cSJustin Hibbits 571*80a5635cSJustin Hibbits uintptr_t 572*80a5635cSJustin Hibbits dtrace_fulword(void *uaddr) 573*80a5635cSJustin Hibbits { 574*80a5635cSJustin Hibbits uintptr_t ret = 0; 575*80a5635cSJustin Hibbits 576*80a5635cSJustin Hibbits if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) { 577*80a5635cSJustin Hibbits if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) { 578*80a5635cSJustin Hibbits DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 579*80a5635cSJustin Hibbits cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 580*80a5635cSJustin Hibbits } 581*80a5635cSJustin Hibbits } 582*80a5635cSJustin Hibbits return ret; 583*80a5635cSJustin Hibbits } 584