diff --git a/sys/cddl/dev/dtrace/aarch64/dtrace_isa.c b/sys/cddl/dev/dtrace/aarch64/dtrace_isa.c index 09dc0b729928..1641ad246419 100644 --- a/sys/cddl/dev/dtrace/aarch64/dtrace_isa.c +++ b/sys/cddl/dev/dtrace/aarch64/dtrace_isa.c @@ -1,398 +1,398 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * $FreeBSD$ */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "regset.h" #define MAX_USTACK_DEPTH 2048 uint8_t dtrace_fuword8_nocheck(void *); uint16_t dtrace_fuword16_nocheck(void *); uint32_t dtrace_fuword32_nocheck(void *); uint64_t dtrace_fuword64_nocheck(void *); void dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, uint32_t *intrpc) { struct unwind_state state; int scp_offset; int depth; depth = 0; if (intrpc != 0) { pcstack[depth++] = (pc_t) intrpc; } aframes++; state.fp = (uintptr_t)__builtin_frame_address(0); state.pc = (uintptr_t)dtrace_getpcstack; while (depth < pcstack_limit) { if (!unwind_frame(curthread, &state)) break; if (!INKERNEL(state.pc)) break; /* * NB: Unlike some other architectures, we don't need to * explicitly insert cpu_dtrace_caller as it appears in the * normal kernel stack trace rather than a special trap frame. */ if (aframes > 0) { aframes--; } else { pcstack[depth++] = state.pc; } } for (; depth < pcstack_limit; depth++) { pcstack[depth] = 0; } } static int dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, uintptr_t fp) { volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; int ret = 0; uintptr_t oldfp = fp; ASSERT(pcstack == NULL || pcstack_limit > 0); while (pc != 0) { /* * We limit the number of times we can go around this * loop to account for a circular stack. */ if (ret++ >= MAX_USTACK_DEPTH) { *flags |= CPU_DTRACE_BADSTACK; cpu_core[curcpu].cpuc_dtrace_illval = fp; break; } if (pcstack != NULL) { *pcstack++ = (uint64_t)pc; pcstack_limit--; if (pcstack_limit <= 0) break; } if (fp == 0) break; pc = dtrace_fuword64((void *)(fp + offsetof(struct arm64_frame, f_retaddr))); fp = dtrace_fuword64((void *)fp); if (fp == oldfp) { *flags |= CPU_DTRACE_BADSTACK; cpu_core[curcpu].cpuc_dtrace_illval = fp; break; } /* * ARM64TODO: * This workaround might not be necessary. It needs to be * revised and removed from all architectures if found * unwanted. Leaving the original x86 comment for reference. * * This is totally bogus: if we faulted, we're going to clear * the fault and break. This is to deal with the apparently * broken Java stacks on x86. */ if (*flags & CPU_DTRACE_FAULT) { *flags &= ~CPU_DTRACE_FAULT; break; } oldfp = fp; } return (ret); } void dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) { proc_t *p = curproc; struct trapframe *tf; uintptr_t pc, fp; volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; int n; if (*flags & CPU_DTRACE_FAULT) return; if (pcstack_limit <= 0) return; /* * If there's no user context we still need to zero the stack. */ if (p == NULL || (tf = curthread->td_frame) == NULL) goto zero; *pcstack++ = (uint64_t)p->p_pid; pcstack_limit--; if (pcstack_limit <= 0) return; pc = tf->tf_elr; fp = tf->tf_x[29]; if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { /* * In an entry probe. The frame pointer has not yet been * pushed (that happens in the function prologue). The * best approach is to add the current pc as a missing top * of stack and back the pc up to the caller, which is stored * at the current stack pointer address since the call * instruction puts it there right before the branch. */ *pcstack++ = (uint64_t)pc; pcstack_limit--; if (pcstack_limit <= 0) return; pc = tf->tf_lr; } n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp); ASSERT(n >= 0); ASSERT(n <= pcstack_limit); pcstack += n; pcstack_limit -= n; zero: while (pcstack_limit-- > 0) *pcstack++ = 0; } int dtrace_getustackdepth(void) { printf("IMPLEMENT ME: %s\n", __func__); return (0); } void dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) { printf("IMPLEMENT ME: %s\n", __func__); } /*ARGSUSED*/ uint64_t dtrace_getarg(int arg, int aframes) { printf("IMPLEMENT ME: %s\n", __func__); return (0); } int dtrace_getstackdepth(int aframes) { struct unwind_state state; int scp_offset; int depth; bool done; depth = 1; done = false; state.fp = (uintptr_t)__builtin_frame_address(0); state.pc = (uintptr_t)dtrace_getstackdepth; do { done = !unwind_frame(curthread, &state); if (!INKERNEL(state.pc) || !INKERNEL(state.fp)) break; depth++; } while (!done); if (depth < aframes) return (0); else return (depth - aframes); } ulong_t -dtrace_getreg(struct trapframe *rp, uint_t reg) +dtrace_getreg(struct trapframe *frame, uint_t reg) { switch (reg) { case REG_X0 ... REG_X29: - return (rp->tf_x[reg]); + return (frame->tf_x[reg]); case REG_LR: - return (rp->tf_lr); + return (frame->tf_lr); case REG_SP: - return (rp->tf_sp); + return (frame->tf_sp); case REG_PC: - return (rp->tf_elr); + return (frame->tf_elr); default: DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); return (0); } /* NOTREACHED */ } static int dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) { if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = uaddr; return (0); } return (1); } void dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, volatile uint16_t *flags) { if (dtrace_copycheck(uaddr, kaddr, size)) dtrace_copy(uaddr, kaddr, size); } void dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, volatile uint16_t *flags) { if (dtrace_copycheck(uaddr, kaddr, size)) dtrace_copy(kaddr, uaddr, size); } void dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, volatile uint16_t *flags) { if (dtrace_copycheck(uaddr, kaddr, size)) dtrace_copystr(uaddr, kaddr, size, flags); } void dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, volatile uint16_t *flags) { if (dtrace_copycheck(uaddr, kaddr, size)) dtrace_copystr(kaddr, uaddr, size, flags); } uint8_t dtrace_fuword8(void *uaddr) { if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword8_nocheck(uaddr)); } uint16_t dtrace_fuword16(void *uaddr) { if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword16_nocheck(uaddr)); } uint32_t dtrace_fuword32(void *uaddr) { if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword32_nocheck(uaddr)); } uint64_t dtrace_fuword64(void *uaddr) { if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword64_nocheck(uaddr)); } diff --git a/sys/cddl/dev/dtrace/amd64/dtrace_isa.c b/sys/cddl/dev/dtrace/amd64/dtrace_isa.c index 55e51cee14d8..503dacdfab1f 100644 --- a/sys/cddl/dev/dtrace/amd64/dtrace_isa.c +++ b/sys/cddl/dev/dtrace/amd64/dtrace_isa.c @@ -1,730 +1,730 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * $FreeBSD$ */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "regset.h" uint8_t dtrace_fuword8_nocheck(void *); uint16_t dtrace_fuword16_nocheck(void *); uint32_t dtrace_fuword32_nocheck(void *); uint64_t dtrace_fuword64_nocheck(void *); int dtrace_ustackdepth_max = 2048; void dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, uint32_t *intrpc) { struct thread *td; int depth = 0; register_t rbp; struct amd64_frame *frame; vm_offset_t callpc; pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; if (intrpc != 0) pcstack[depth++] = (pc_t) intrpc; aframes++; __asm __volatile("movq %%rbp,%0" : "=r" (rbp)); frame = (struct amd64_frame *)rbp; td = curthread; while (depth < pcstack_limit) { if (!kstack_contains(curthread, (vm_offset_t)frame, sizeof(*frame))) break; callpc = frame->f_retaddr; if (!INKERNEL(callpc)) break; if (aframes > 0) { aframes--; if ((aframes == 0) && (caller != 0)) { pcstack[depth++] = caller; } } else { pcstack[depth++] = callpc; } if ((vm_offset_t)frame->f_frame <= (vm_offset_t)frame) break; frame = frame->f_frame; } for (; depth < pcstack_limit; depth++) { pcstack[depth] = 0; } } static int dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, uintptr_t sp) { uintptr_t oldsp; volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; int ret = 0; ASSERT(pcstack == NULL || pcstack_limit > 0); ASSERT(dtrace_ustackdepth_max > 0); while (pc != 0) { /* * We limit the number of times we can go around this * loop to account for a circular stack. */ if (ret++ >= dtrace_ustackdepth_max) { *flags |= CPU_DTRACE_BADSTACK; cpu_core[curcpu].cpuc_dtrace_illval = sp; break; } if (pcstack != NULL) { *pcstack++ = (uint64_t)pc; pcstack_limit--; if (pcstack_limit <= 0) break; } if (sp == 0) break; oldsp = sp; pc = dtrace_fuword64((void *)(sp + offsetof(struct amd64_frame, f_retaddr))); sp = dtrace_fuword64((void *)sp); if (sp == oldsp) { *flags |= CPU_DTRACE_BADSTACK; cpu_core[curcpu].cpuc_dtrace_illval = sp; break; } /* * This is totally bogus: if we faulted, we're going to clear * the fault and break. This is to deal with the apparently * broken Java stacks on x86. */ if (*flags & CPU_DTRACE_FAULT) { *flags &= ~CPU_DTRACE_FAULT; break; } } return (ret); } void dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) { proc_t *p = curproc; struct trapframe *tf; uintptr_t pc, sp, fp; volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; int n; if (*flags & CPU_DTRACE_FAULT) return; if (pcstack_limit <= 0) return; /* * If there's no user context we still need to zero the stack. */ if (p == NULL || (tf = curthread->td_frame) == NULL) goto zero; *pcstack++ = (uint64_t)p->p_pid; pcstack_limit--; if (pcstack_limit <= 0) return; pc = tf->tf_rip; fp = tf->tf_rbp; sp = tf->tf_rsp; if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { /* * In an entry probe. The frame pointer has not yet been * pushed (that happens in the function prologue). The * best approach is to add the current pc as a missing top * of stack and back the pc up to the caller, which is stored * at the current stack pointer address since the call * instruction puts it there right before the branch. */ *pcstack++ = (uint64_t)pc; pcstack_limit--; if (pcstack_limit <= 0) return; pc = dtrace_fuword64((void *) sp); } n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp); ASSERT(n >= 0); ASSERT(n <= pcstack_limit); pcstack += n; pcstack_limit -= n; zero: while (pcstack_limit-- > 0) *pcstack++ = 0; } int dtrace_getustackdepth(void) { proc_t *p = curproc; struct trapframe *tf; uintptr_t pc, fp, sp; int n = 0; if (p == NULL || (tf = curthread->td_frame) == NULL) return (0); if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) return (-1); pc = tf->tf_rip; fp = tf->tf_rbp; sp = tf->tf_rsp; if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { /* * In an entry probe. The frame pointer has not yet been * pushed (that happens in the function prologue). The * best approach is to add the current pc as a missing top * of stack and back the pc up to the caller, which is stored * at the current stack pointer address since the call * instruction puts it there right before the branch. */ pc = dtrace_fuword64((void *) sp); n++; } n += dtrace_getustack_common(NULL, 0, pc, fp); return (n); } void dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) { proc_t *p = curproc; struct trapframe *tf; uintptr_t pc, sp, fp; volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; #ifdef notyet /* XXX signal stack */ uintptr_t oldcontext; size_t s1, s2; #endif if (*flags & CPU_DTRACE_FAULT) return; if (pcstack_limit <= 0) return; /* * If there's no user context we still need to zero the stack. */ if (p == NULL || (tf = curthread->td_frame) == NULL) goto zero; *pcstack++ = (uint64_t)p->p_pid; pcstack_limit--; if (pcstack_limit <= 0) return; pc = tf->tf_rip; sp = tf->tf_rsp; fp = tf->tf_rbp; #ifdef notyet /* XXX signal stack */ oldcontext = lwp->lwp_oldcontext; s1 = sizeof (struct xframe) + 2 * sizeof (long); s2 = s1 + sizeof (siginfo_t); #endif if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { *pcstack++ = (uint64_t)pc; *fpstack++ = 0; pcstack_limit--; if (pcstack_limit <= 0) return; pc = dtrace_fuword64((void *)sp); } while (pc != 0) { *pcstack++ = (uint64_t)pc; *fpstack++ = fp; pcstack_limit--; if (pcstack_limit <= 0) break; if (fp == 0) break; #ifdef notyet /* XXX signal stack */ if (oldcontext == sp + s1 || oldcontext == sp + s2) { ucontext_t *ucp = (ucontext_t *)oldcontext; greg_t *gregs = ucp->uc_mcontext.gregs; sp = dtrace_fulword(&gregs[REG_FP]); pc = dtrace_fulword(&gregs[REG_PC]); oldcontext = dtrace_fulword(&ucp->uc_link); } else #endif /* XXX */ { pc = dtrace_fuword64((void *)(fp + offsetof(struct amd64_frame, f_retaddr))); fp = dtrace_fuword64((void *)fp); } /* * This is totally bogus: if we faulted, we're going to clear * the fault and break. This is to deal with the apparently * broken Java stacks on x86. */ if (*flags & CPU_DTRACE_FAULT) { *flags &= ~CPU_DTRACE_FAULT; break; } } zero: while (pcstack_limit-- > 0) *pcstack++ = 0; } /*ARGSUSED*/ uint64_t dtrace_getarg(int arg, int aframes) { uintptr_t val; struct amd64_frame *fp = (struct amd64_frame *)dtrace_getfp(); uintptr_t *stack; int i; /* * A total of 6 arguments are passed via registers; any argument with * index of 5 or lower is therefore in a register. */ int inreg = 5; for (i = 1; i <= aframes; i++) { fp = fp->f_frame; if (P2ROUNDUP(fp->f_retaddr, 16) == (long)dtrace_invop_callsite) { /* * In the case of amd64, we will use the pointer to the * regs structure that was pushed when we took the * trap. To get this structure, we must increment * beyond the frame structure, and then again beyond * the calling RIP stored in dtrace_invop(). If the * argument that we're seeking is passed on the stack, * we'll pull the true stack pointer out of the saved * registers and decrement our argument by the number * of arguments passed in registers; if the argument * we're seeking is passed in registers, we can just * load it directly. */ struct trapframe *tf = (struct trapframe *)&fp[1]; if (arg <= inreg) { switch (arg) { case 0: stack = (uintptr_t *)&tf->tf_rdi; break; case 1: stack = (uintptr_t *)&tf->tf_rsi; break; case 2: stack = (uintptr_t *)&tf->tf_rdx; break; case 3: stack = (uintptr_t *)&tf->tf_rcx; break; case 4: stack = (uintptr_t *)&tf->tf_r8; break; case 5: stack = (uintptr_t *)&tf->tf_r9; break; } arg = 0; } else { stack = (uintptr_t *)(tf->tf_rsp); arg -= inreg; } goto load; } } /* * We know that we did not come through a trap to get into * dtrace_probe() -- the provider simply called dtrace_probe() * directly. As this is the case, we need to shift the argument * that we're looking for: the probe ID is the first argument to * dtrace_probe(), so the argument n will actually be found where * one would expect to find argument (n + 1). */ arg++; if (arg <= inreg) { /* * This shouldn't happen. If the argument is passed in a * register then it should have been, well, passed in a * register... */ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); return (0); } arg -= (inreg + 1); stack = (uintptr_t *)&fp[1]; load: DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); val = stack[arg]; DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); return (val); } int dtrace_getstackdepth(int aframes) { int depth = 0; struct amd64_frame *frame; vm_offset_t rbp; aframes++; rbp = dtrace_getfp(); frame = (struct amd64_frame *)rbp; depth++; for(;;) { if (!kstack_contains(curthread, (vm_offset_t)frame, sizeof(*frame))) break; depth++; if (frame->f_frame <= frame) break; frame = frame->f_frame; } if (depth < aframes) return 0; else return depth - aframes; } ulong_t -dtrace_getreg(struct trapframe *rp, uint_t reg) +dtrace_getreg(struct trapframe *frame, uint_t reg) { /* This table is dependent on reg.d. */ int regmap[] = { REG_GS, /* 0 GS */ REG_FS, /* 1 FS */ REG_ES, /* 2 ES */ REG_DS, /* 3 DS */ REG_RDI, /* 4 EDI */ REG_RSI, /* 5 ESI */ REG_RBP, /* 6 EBP, REG_FP */ REG_RSP, /* 7 ESP */ REG_RBX, /* 8 EBX, REG_R1 */ REG_RDX, /* 9 EDX */ REG_RCX, /* 10 ECX */ REG_RAX, /* 11 EAX, REG_R0 */ REG_TRAPNO, /* 12 TRAPNO */ REG_ERR, /* 13 ERR */ REG_RIP, /* 14 EIP, REG_PC */ REG_CS, /* 15 CS */ REG_RFL, /* 16 EFL, REG_PS */ REG_RSP, /* 17 UESP, REG_SP */ REG_SS /* 18 SS */ }; if (reg <= GS) { if (reg >= sizeof (regmap) / sizeof (int)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); return (0); } reg = regmap[reg]; } else { /* This is dependent on reg.d. */ reg -= GS + 1; } switch (reg) { case REG_RDI: - return (rp->tf_rdi); + return (frame->tf_rdi); case REG_RSI: - return (rp->tf_rsi); + return (frame->tf_rsi); case REG_RDX: - return (rp->tf_rdx); + return (frame->tf_rdx); case REG_RCX: - return (rp->tf_rcx); + return (frame->tf_rcx); case REG_R8: - return (rp->tf_r8); + return (frame->tf_r8); case REG_R9: - return (rp->tf_r9); + return (frame->tf_r9); case REG_RAX: - return (rp->tf_rax); + return (frame->tf_rax); case REG_RBX: - return (rp->tf_rbx); + return (frame->tf_rbx); case REG_RBP: - return (rp->tf_rbp); + return (frame->tf_rbp); case REG_R10: - return (rp->tf_r10); + return (frame->tf_r10); case REG_R11: - return (rp->tf_r11); + return (frame->tf_r11); case REG_R12: - return (rp->tf_r12); + return (frame->tf_r12); case REG_R13: - return (rp->tf_r13); + return (frame->tf_r13); case REG_R14: - return (rp->tf_r14); + return (frame->tf_r14); case REG_R15: - return (rp->tf_r15); + return (frame->tf_r15); case REG_DS: - return (rp->tf_ds); + return (frame->tf_ds); case REG_ES: - return (rp->tf_es); + return (frame->tf_es); case REG_FS: - return (rp->tf_fs); + return (frame->tf_fs); case REG_GS: - return (rp->tf_gs); + return (frame->tf_gs); case REG_TRAPNO: - return (rp->tf_trapno); + return (frame->tf_trapno); case REG_ERR: - return (rp->tf_err); + return (frame->tf_err); case REG_RIP: - return (rp->tf_rip); + return (frame->tf_rip); case REG_CS: - return (rp->tf_cs); + return (frame->tf_cs); case REG_SS: - return (rp->tf_ss); + return (frame->tf_ss); case REG_RFL: - return (rp->tf_rflags); + return (frame->tf_rflags); case REG_RSP: - return (rp->tf_rsp); + return (frame->tf_rsp); default: DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); return (0); } } static int dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) { ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr); if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = uaddr; return (0); } return (1); } void dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, volatile uint16_t *flags) { if (dtrace_copycheck(uaddr, kaddr, size)) dtrace_copy(uaddr, kaddr, size); } void dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, volatile uint16_t *flags) { if (dtrace_copycheck(uaddr, kaddr, size)) dtrace_copy(kaddr, uaddr, size); } void dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, volatile uint16_t *flags) { if (dtrace_copycheck(uaddr, kaddr, size)) dtrace_copystr(uaddr, kaddr, size, flags); } void dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, volatile uint16_t *flags) { if (dtrace_copycheck(uaddr, kaddr, size)) dtrace_copystr(kaddr, uaddr, size, flags); } uint8_t dtrace_fuword8(void *uaddr) { if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword8_nocheck(uaddr)); } uint16_t dtrace_fuword16(void *uaddr) { if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword16_nocheck(uaddr)); } uint32_t dtrace_fuword32(void *uaddr) { if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword32_nocheck(uaddr)); } uint64_t dtrace_fuword64(void *uaddr) { if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword64_nocheck(uaddr)); } /* * ifunc resolvers for SMAP support */ void dtrace_copy_nosmap(uintptr_t, uintptr_t, size_t); void dtrace_copy_smap(uintptr_t, uintptr_t, size_t); DEFINE_IFUNC(, void, dtrace_copy, (uintptr_t, uintptr_t, size_t)) { return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? dtrace_copy_smap : dtrace_copy_nosmap); } void dtrace_copystr_nosmap(uintptr_t, uintptr_t, size_t, volatile uint16_t *); void dtrace_copystr_smap(uintptr_t, uintptr_t, size_t, volatile uint16_t *); DEFINE_IFUNC(, void, dtrace_copystr, (uintptr_t, uintptr_t, size_t, volatile uint16_t *)) { return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? dtrace_copystr_smap : dtrace_copystr_nosmap); } uintptr_t dtrace_fulword_nosmap(void *); uintptr_t dtrace_fulword_smap(void *); DEFINE_IFUNC(, uintptr_t, dtrace_fulword, (void *)) { return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? dtrace_fulword_smap : dtrace_fulword_nosmap); } uint8_t dtrace_fuword8_nocheck_nosmap(void *); uint8_t dtrace_fuword8_nocheck_smap(void *); DEFINE_IFUNC(, uint8_t, dtrace_fuword8_nocheck, (void *)) { return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? dtrace_fuword8_nocheck_smap : dtrace_fuword8_nocheck_nosmap); } uint16_t dtrace_fuword16_nocheck_nosmap(void *); uint16_t dtrace_fuword16_nocheck_smap(void *); DEFINE_IFUNC(, uint16_t, dtrace_fuword16_nocheck, (void *)) { return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? dtrace_fuword16_nocheck_smap : dtrace_fuword16_nocheck_nosmap); } uint32_t dtrace_fuword32_nocheck_nosmap(void *); uint32_t dtrace_fuword32_nocheck_smap(void *); DEFINE_IFUNC(, uint32_t, dtrace_fuword32_nocheck, (void *)) { return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? dtrace_fuword32_nocheck_smap : dtrace_fuword32_nocheck_nosmap); } uint64_t dtrace_fuword64_nocheck_nosmap(void *); uint64_t dtrace_fuword64_nocheck_smap(void *); DEFINE_IFUNC(, uint64_t, dtrace_fuword64_nocheck, (void *)) { return ((cpu_stdext_feature & CPUID_STDEXT_SMAP) != 0 ? dtrace_fuword64_nocheck_smap : dtrace_fuword64_nocheck_nosmap); } diff --git a/sys/cddl/dev/dtrace/arm/dtrace_isa.c b/sys/cddl/dev/dtrace/arm/dtrace_isa.c index e6fba2d09be8..c50f9210f5dc 100644 --- a/sys/cddl/dev/dtrace/arm/dtrace_isa.c +++ b/sys/cddl/dev/dtrace/arm/dtrace_isa.c @@ -1,254 +1,254 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * $FreeBSD$ */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "regset.h" uint8_t dtrace_fuword8_nocheck(void *); uint16_t dtrace_fuword16_nocheck(void *); uint32_t dtrace_fuword32_nocheck(void *); uint64_t dtrace_fuword64_nocheck(void *); void dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, uint32_t *intrpc) { struct unwind_state state; register_t sp; int scp_offset; int depth = 0; if (intrpc != 0) pcstack[depth++] = (pc_t) intrpc; aframes++; __asm __volatile("mov %0, sp" : "=&r" (sp)); state.registers[FP] = (uint32_t)__builtin_frame_address(0); state.registers[SP] = sp; state.registers[LR] = (uint32_t)__builtin_return_address(0); state.registers[PC] = (uint32_t)dtrace_getpcstack; while (depth < pcstack_limit) { int done; done = unwind_stack_one(&state, 1); /* * NB: Unlike some other architectures, we don't need to * explicitly insert cpu_dtrace_caller as it appears in the * normal kernel stack trace rather than a special trap frame. */ if (aframes > 0) { aframes--; } else { pcstack[depth++] = state.registers[PC]; } if (done) break; } for (; depth < pcstack_limit; depth++) { pcstack[depth] = 0; } } void dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) { printf("IMPLEMENT ME: %s\n", __func__); } int dtrace_getustackdepth(void) { printf("IMPLEMENT ME: %s\n", __func__); return (0); } void dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) { printf("IMPLEMENT ME: %s\n", __func__); } /*ARGSUSED*/ uint64_t dtrace_getarg(int arg, int aframes) { /* struct arm_frame *fp = (struct arm_frame *)dtrace_getfp();*/ return (0); } int dtrace_getstackdepth(int aframes) { struct unwind_state state; register_t sp; int scp_offset; int done = 0; int depth = 1; __asm __volatile("mov %0, sp" : "=&r" (sp)); state.registers[FP] = (uint32_t)__builtin_frame_address(0); state.registers[SP] = sp; state.registers[LR] = (uint32_t)__builtin_return_address(0); state.registers[PC] = (uint32_t)dtrace_getstackdepth; do { done = unwind_stack_one(&state, 1); depth++; } while (!done); if (depth < aframes) return 0; else return depth - aframes; } ulong_t -dtrace_getreg(struct trapframe *rp, uint_t reg) +dtrace_getreg(struct trapframe *frame, uint_t reg) { printf("IMPLEMENT ME: %s\n", __func__); return (0); } static int dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) { if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = uaddr; return (0); } return (1); } void dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, volatile uint16_t *flags) { if (dtrace_copycheck(uaddr, kaddr, size)) dtrace_copy(uaddr, kaddr, size); } void dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, volatile uint16_t *flags) { if (dtrace_copycheck(uaddr, kaddr, size)) dtrace_copy(kaddr, uaddr, size); } void dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, volatile uint16_t *flags) { if (dtrace_copycheck(uaddr, kaddr, size)) dtrace_copystr(uaddr, kaddr, size, flags); } void dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, volatile uint16_t *flags) { if (dtrace_copycheck(uaddr, kaddr, size)) dtrace_copystr(kaddr, uaddr, size, flags); } uint8_t dtrace_fuword8(void *uaddr) { if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword8_nocheck(uaddr)); } uint16_t dtrace_fuword16(void *uaddr) { if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword16_nocheck(uaddr)); } uint32_t dtrace_fuword32(void *uaddr) { if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword32_nocheck(uaddr)); } uint64_t dtrace_fuword64(void *uaddr) { if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword64_nocheck(uaddr)); } diff --git a/sys/cddl/dev/dtrace/i386/dtrace_isa.c b/sys/cddl/dev/dtrace/i386/dtrace_isa.c index 3c8602c1f7be..53a6aceffa73 100644 --- a/sys/cddl/dev/dtrace/i386/dtrace_isa.c +++ b/sys/cddl/dev/dtrace/i386/dtrace_isa.c @@ -1,675 +1,675 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * $FreeBSD$ */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "regset.h" extern uintptr_t kernbase; uintptr_t kernelbase = (uintptr_t) &kernbase; uint8_t dtrace_fuword8_nocheck(void *); uint16_t dtrace_fuword16_nocheck(void *); uint32_t dtrace_fuword32_nocheck(void *); uint64_t dtrace_fuword64_nocheck(void *); int dtrace_ustackdepth_max = 2048; void dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, uint32_t *intrpc) { int depth = 0; register_t ebp; struct i386_frame *frame; vm_offset_t callpc; pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; if (intrpc != 0) pcstack[depth++] = (pc_t) intrpc; aframes++; __asm __volatile("movl %%ebp,%0" : "=r" (ebp)); frame = (struct i386_frame *)ebp; while (depth < pcstack_limit) { if (!kstack_contains(curthread, (vm_offset_t)frame, sizeof(*frame))) break; callpc = frame->f_retaddr; if (!INKERNEL(callpc)) break; if (aframes > 0) { aframes--; if ((aframes == 0) && (caller != 0)) { pcstack[depth++] = caller; } } else { pcstack[depth++] = callpc; } if (frame->f_frame <= frame) break; frame = frame->f_frame; } for (; depth < pcstack_limit; depth++) { pcstack[depth] = 0; } } static int dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, uintptr_t sp) { #ifdef notyet proc_t *p = curproc; uintptr_t oldcontext = lwp->lwp_oldcontext; /* XXX signal stack. */ size_t s1, s2; #endif uintptr_t oldsp; volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; int ret = 0; ASSERT(pcstack == NULL || pcstack_limit > 0); ASSERT(dtrace_ustackdepth_max > 0); #ifdef notyet /* XXX signal stack. */ if (p->p_model == DATAMODEL_NATIVE) { s1 = sizeof (struct frame) + 2 * sizeof (long); s2 = s1 + sizeof (siginfo_t); } else { s1 = sizeof (struct frame32) + 3 * sizeof (int); s2 = s1 + sizeof (siginfo32_t); } #endif while (pc != 0) { /* * We limit the number of times we can go around this * loop to account for a circular stack. */ if (ret++ >= dtrace_ustackdepth_max) { *flags |= CPU_DTRACE_BADSTACK; cpu_core[curcpu].cpuc_dtrace_illval = sp; break; } if (pcstack != NULL) { *pcstack++ = (uint64_t)pc; pcstack_limit--; if (pcstack_limit <= 0) break; } if (sp == 0) break; oldsp = sp; #ifdef notyet /* XXX signal stack. */ if (oldcontext == sp + s1 || oldcontext == sp + s2) { if (p->p_model == DATAMODEL_NATIVE) { ucontext_t *ucp = (ucontext_t *)oldcontext; greg_t *gregs = ucp->uc_mcontext.gregs; sp = dtrace_fulword(&gregs[REG_FP]); pc = dtrace_fulword(&gregs[REG_PC]); oldcontext = dtrace_fulword(&ucp->uc_link); } else { ucontext32_t *ucp = (ucontext32_t *)oldcontext; greg32_t *gregs = ucp->uc_mcontext.gregs; sp = dtrace_fuword32(&gregs[EBP]); pc = dtrace_fuword32(&gregs[EIP]); oldcontext = dtrace_fuword32(&ucp->uc_link); } } else { if (p->p_model == DATAMODEL_NATIVE) { struct frame *fr = (struct frame *)sp; pc = dtrace_fulword(&fr->fr_savpc); sp = dtrace_fulword(&fr->fr_savfp); } else { struct frame32 *fr = (struct frame32 *)sp; pc = dtrace_fuword32(&fr->fr_savpc); sp = dtrace_fuword32(&fr->fr_savfp); } } #else pc = dtrace_fuword32((void *)(sp + offsetof(struct i386_frame, f_retaddr))); sp = dtrace_fuword32((void *)sp); #endif /* ! notyet */ if (sp == oldsp) { *flags |= CPU_DTRACE_BADSTACK; cpu_core[curcpu].cpuc_dtrace_illval = sp; break; } /* * This is totally bogus: if we faulted, we're going to clear * the fault and break. This is to deal with the apparently * broken Java stacks on x86. */ if (*flags & CPU_DTRACE_FAULT) { *flags &= ~CPU_DTRACE_FAULT; break; } } return (ret); } void dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) { proc_t *p = curproc; struct trapframe *tf; uintptr_t pc, sp, fp; volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; int n; if (*flags & CPU_DTRACE_FAULT) return; if (pcstack_limit <= 0) return; /* * If there's no user context we still need to zero the stack. */ if (p == NULL || (tf = curthread->td_frame) == NULL) goto zero; *pcstack++ = (uint64_t)p->p_pid; pcstack_limit--; if (pcstack_limit <= 0) return; pc = tf->tf_eip; fp = tf->tf_ebp; sp = tf->tf_esp; if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { /* * In an entry probe. The frame pointer has not yet been * pushed (that happens in the function prologue). The * best approach is to add the current pc as a missing top * of stack and back the pc up to the caller, which is stored * at the current stack pointer address since the call * instruction puts it there right before the branch. */ *pcstack++ = (uint64_t)pc; pcstack_limit--; if (pcstack_limit <= 0) return; pc = dtrace_fuword32((void *) sp); } n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp); ASSERT(n >= 0); ASSERT(n <= pcstack_limit); pcstack += n; pcstack_limit -= n; zero: while (pcstack_limit-- > 0) *pcstack++ = 0; } int dtrace_getustackdepth(void) { proc_t *p = curproc; struct trapframe *tf; uintptr_t pc, fp, sp; int n = 0; if (p == NULL || (tf = curthread->td_frame) == NULL) return (0); if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) return (-1); pc = tf->tf_eip; fp = tf->tf_ebp; sp = tf->tf_esp; if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { /* * In an entry probe. The frame pointer has not yet been * pushed (that happens in the function prologue). The * best approach is to add the current pc as a missing top * of stack and back the pc up to the caller, which is stored * at the current stack pointer address since the call * instruction puts it there right before the branch. */ pc = dtrace_fuword32((void *) sp); n++; } n += dtrace_getustack_common(NULL, 0, pc, fp); return (n); } void dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) { proc_t *p = curproc; struct trapframe *tf; uintptr_t pc, sp, fp; volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; #ifdef notyet /* XXX signal stack */ uintptr_t oldcontext; size_t s1, s2; #endif if (*flags & CPU_DTRACE_FAULT) return; if (pcstack_limit <= 0) return; /* * If there's no user context we still need to zero the stack. */ if (p == NULL || (tf = curthread->td_frame) == NULL) goto zero; *pcstack++ = (uint64_t)p->p_pid; pcstack_limit--; if (pcstack_limit <= 0) return; pc = tf->tf_eip; fp = tf->tf_ebp; sp = tf->tf_esp; #ifdef notyet /* XXX signal stack */ oldcontext = lwp->lwp_oldcontext; if (p->p_model == DATAMODEL_NATIVE) { s1 = sizeof (struct frame) + 2 * sizeof (long); s2 = s1 + sizeof (siginfo_t); } else { s1 = sizeof (struct frame32) + 3 * sizeof (int); s2 = s1 + sizeof (siginfo32_t); } #endif if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { *pcstack++ = (uint64_t)pc; *fpstack++ = 0; pcstack_limit--; if (pcstack_limit <= 0) return; pc = dtrace_fuword32((void *)sp); } while (pc != 0) { *pcstack++ = (uint64_t)pc; *fpstack++ = fp; pcstack_limit--; if (pcstack_limit <= 0) break; if (fp == 0) break; #ifdef notyet /* XXX signal stack */ if (oldcontext == sp + s1 || oldcontext == sp + s2) { if (p->p_model == DATAMODEL_NATIVE) { ucontext_t *ucp = (ucontext_t *)oldcontext; greg_t *gregs = ucp->uc_mcontext.gregs; sp = dtrace_fulword(&gregs[REG_FP]); pc = dtrace_fulword(&gregs[REG_PC]); oldcontext = dtrace_fulword(&ucp->uc_link); } else { ucontext_t *ucp = (ucontext_t *)oldcontext; greg_t *gregs = ucp->uc_mcontext.gregs; sp = dtrace_fuword32(&gregs[EBP]); pc = dtrace_fuword32(&gregs[EIP]); oldcontext = dtrace_fuword32(&ucp->uc_link); } } else #endif /* XXX */ { pc = dtrace_fuword32((void *)(fp + offsetof(struct i386_frame, f_retaddr))); fp = dtrace_fuword32((void *)fp); } /* * This is totally bogus: if we faulted, we're going to clear * the fault and break. This is to deal with the apparently * broken Java stacks on x86. */ if (*flags & CPU_DTRACE_FAULT) { *flags &= ~CPU_DTRACE_FAULT; break; } } zero: while (pcstack_limit-- > 0) *pcstack++ = 0; } uint64_t dtrace_getarg(int arg, int aframes) { struct trapframe *frame; struct i386_frame *fp = (struct i386_frame *)dtrace_getfp(); uintptr_t *stack, val; int i; for (i = 1; i <= aframes; i++) { fp = fp->f_frame; if (P2ROUNDUP(fp->f_retaddr, 4) == (long)dtrace_invop_callsite) { /* * If we pass through the invalid op handler, we will * use the trap frame pointer that it pushed on the * stack as the second argument to dtrace_invop() as * the pointer to the stack. When using this stack, we * must skip the third argument to dtrace_invop(), * which is included in the i386_frame. */ frame = (struct trapframe *)(((uintptr_t **)&fp[1])[0]); /* * Skip the three hardware-saved registers and the * return address. */ stack = (uintptr_t *)frame->tf_isp + 4; goto load; } } /* * We know that we did not come through a trap to get into * dtrace_probe() -- the provider simply called dtrace_probe() * directly. As this is the case, we need to shift the argument * that we're looking for: the probe ID is the first argument to * dtrace_probe(), so the argument n will actually be found where * one would expect to find argument (n + 1). */ arg++; stack = (uintptr_t *)fp + 2; load: DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); val = stack[arg]; DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); return (val); } int dtrace_getstackdepth(int aframes) { int depth = 0; struct i386_frame *frame; vm_offset_t ebp; aframes++; ebp = dtrace_getfp(); frame = (struct i386_frame *)ebp; depth++; for(;;) { if (!kstack_contains(curthread, (vm_offset_t)frame, sizeof(*frame))) break; depth++; if (frame->f_frame <= frame) break; frame = frame->f_frame; } if (depth < aframes) return 0; else return depth - aframes; } ulong_t -dtrace_getreg(struct trapframe *rp, uint_t reg) +dtrace_getreg(struct trapframe *frame, uint_t reg) { struct pcb *pcb; int regmap[] = { /* Order is dependent on reg.d */ REG_GS, /* 0 GS */ REG_FS, /* 1 FS */ REG_ES, /* 2 ES */ REG_DS, /* 3 DS */ REG_RDI, /* 4 EDI */ REG_RSI, /* 5 ESI */ REG_RBP, /* 6 EBP, REG_FP */ REG_RSP, /* 7 ESP */ REG_RBX, /* 8 EBX */ REG_RDX, /* 9 EDX, REG_R1 */ REG_RCX, /* 10 ECX */ REG_RAX, /* 11 EAX, REG_R0 */ REG_TRAPNO, /* 12 TRAPNO */ REG_ERR, /* 13 ERR */ REG_RIP, /* 14 EIP, REG_PC */ REG_CS, /* 15 CS */ REG_RFL, /* 16 EFL, REG_PS */ REG_RSP, /* 17 UESP, REG_SP */ REG_SS /* 18 SS */ }; if (reg > SS) { DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); return (0); } if (reg >= sizeof (regmap) / sizeof (int)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); return (0); } reg = regmap[reg]; switch(reg) { case REG_GS: if ((pcb = curthread->td_pcb) == NULL) { DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); return (0); } return (pcb->pcb_gs); case REG_FS: - return (rp->tf_fs); + return (frame->tf_fs); case REG_ES: - return (rp->tf_es); + return (frame->tf_es); case REG_DS: - return (rp->tf_ds); + return (frame->tf_ds); case REG_RDI: - return (rp->tf_edi); + return (frame->tf_edi); case REG_RSI: - return (rp->tf_esi); + return (frame->tf_esi); case REG_RBP: - return (rp->tf_ebp); + return (frame->tf_ebp); case REG_RSP: - return (rp->tf_isp); + return (frame->tf_isp); case REG_RBX: - return (rp->tf_ebx); + return (frame->tf_ebx); case REG_RCX: - return (rp->tf_ecx); + return (frame->tf_ecx); case REG_RAX: - return (rp->tf_eax); + return (frame->tf_eax); case REG_TRAPNO: - return (rp->tf_trapno); + return (frame->tf_trapno); case REG_ERR: - return (rp->tf_err); + return (frame->tf_err); case REG_RIP: - return (rp->tf_eip); + return (frame->tf_eip); case REG_CS: - return (rp->tf_cs); + return (frame->tf_cs); case REG_RFL: - return (rp->tf_eflags); + return (frame->tf_eflags); #if 0 case REG_RSP: - return (rp->tf_esp); + return (frame->tf_esp); #endif case REG_SS: - return (rp->tf_ss); + return (frame->tf_ss); default: DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); return (0); } } static int dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) { ASSERT(kaddr >= kernelbase && kaddr + size >= kaddr); if (uaddr + size >= kernelbase || uaddr + size < uaddr) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = uaddr; return (0); } return (1); } void dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, volatile uint16_t *flags) { if (dtrace_copycheck(uaddr, kaddr, size)) dtrace_copy(uaddr, kaddr, size); } void dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, volatile uint16_t *flags) { if (dtrace_copycheck(uaddr, kaddr, size)) dtrace_copy(kaddr, uaddr, size); } void dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, volatile uint16_t *flags) { if (dtrace_copycheck(uaddr, kaddr, size)) dtrace_copystr(uaddr, kaddr, size, flags); } void dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, volatile uint16_t *flags) { if (dtrace_copycheck(uaddr, kaddr, size)) dtrace_copystr(kaddr, uaddr, size, flags); } uint8_t dtrace_fuword8(void *uaddr) { if ((uintptr_t)uaddr >= kernelbase) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword8_nocheck(uaddr)); } uint16_t dtrace_fuword16(void *uaddr) { if ((uintptr_t)uaddr >= kernelbase) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword16_nocheck(uaddr)); } uint32_t dtrace_fuword32(void *uaddr) { if ((uintptr_t)uaddr >= kernelbase) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword32_nocheck(uaddr)); } uint64_t dtrace_fuword64(void *uaddr) { if ((uintptr_t)uaddr >= kernelbase) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword64_nocheck(uaddr)); } diff --git a/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c b/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c index 1fca72e5b7fd..d95dce4e32e4 100644 --- a/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c +++ b/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c @@ -1,699 +1,699 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Portions Copyright 2012,2013 Justin Hibbits * * $FreeBSD$ */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "regset.h" /* Offset to the LR Save word (ppc32) */ #define RETURN_OFFSET 4 /* Offset to LR Save word (ppc64). CR Save area sits between back chain and LR */ #define RETURN_OFFSET64 16 #ifdef __powerpc64__ #define OFFSET 4 /* Account for the TOC reload slot */ #define FRAME_OFFSET 48 #else #define OFFSET 0 #define FRAME_OFFSET 8 #endif #define INKERNEL(x) (((x) <= VM_MAX_KERNEL_ADDRESS && \ (x) >= VM_MIN_KERNEL_ADDRESS) || \ (PMAP_HAS_DMAP && (x) >= DMAP_BASE_ADDRESS && \ (x) <= DMAP_MAX_ADDRESS)) static __inline int dtrace_sp_inkernel(uintptr_t sp) { struct trapframe *frame; vm_offset_t callpc; /* Not within the kernel, or not aligned. */ if (!INKERNEL(sp) || (sp & 0xf) != 0) return (0); #ifdef __powerpc64__ callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64); #else callpc = *(vm_offset_t *)(sp + RETURN_OFFSET); #endif if ((callpc & 3) || (callpc < 0x100)) return (0); /* * trapexit() and asttrapexit() are sentinels * for kernel stack tracing. */ if (callpc + OFFSET == (vm_offset_t) &trapexit || callpc + OFFSET == (vm_offset_t) &asttrapexit) { frame = (struct trapframe *)(sp + FRAME_OFFSET); return ((frame->srr1 & PSL_PR) == 0); } return (1); } static __inline void dtrace_next_sp_pc(uintptr_t sp, uintptr_t *nsp, uintptr_t *pc, uintptr_t *lr) { vm_offset_t callpc; struct trapframe *frame; if (lr != 0 && *lr != 0) callpc = *lr; else #ifdef __powerpc64__ callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64); #else callpc = *(vm_offset_t *)(sp + RETURN_OFFSET); #endif /* * trapexit() and asttrapexit() are sentinels * for kernel stack tracing. */ if ((callpc + OFFSET == (vm_offset_t) &trapexit || callpc + OFFSET == (vm_offset_t) &asttrapexit)) { /* Access the trap frame */ frame = (struct trapframe *)(sp + FRAME_OFFSET); if (nsp != NULL) *nsp = frame->fixreg[1]; if (pc != NULL) *pc = frame->srr0; if (lr != NULL) *lr = frame->lr; return; } if (nsp != NULL) *nsp = *(uintptr_t *)sp; if (pc != NULL) *pc = callpc; /* lr is only valid for trap frames */ if (lr != NULL) *lr = 0; } void dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, uint32_t *intrpc) { int depth = 0; uintptr_t osp, sp, lr = 0; vm_offset_t callpc; pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; osp = PAGE_SIZE; if (intrpc != 0) pcstack[depth++] = (pc_t) intrpc; aframes++; sp = (uintptr_t)__builtin_frame_address(0); while (depth < pcstack_limit) { if (sp <= osp) break; if (!dtrace_sp_inkernel(sp)) break; osp = sp; dtrace_next_sp_pc(osp, &sp, &callpc, &lr); if (aframes > 0) { aframes--; if ((aframes == 0) && (caller != 0)) { pcstack[depth++] = caller; } } else { pcstack[depth++] = callpc; } } for (; depth < pcstack_limit; depth++) { pcstack[depth] = 0; } } static int dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, uintptr_t sp) { proc_t *p = curproc; int ret = 0; ASSERT(pcstack == NULL || pcstack_limit > 0); while (pc != 0) { ret++; if (pcstack != NULL) { *pcstack++ = (uint64_t)pc; pcstack_limit--; if (pcstack_limit <= 0) break; } if (sp == 0) break; if (SV_PROC_FLAG(p, SV_ILP32)) { pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET)); sp = dtrace_fuword32((void *)sp); } else { pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64)); sp = dtrace_fuword64((void *)sp); } } return (ret); } void dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) { proc_t *p = curproc; struct trapframe *tf; uintptr_t pc, sp; volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; int n; if (*flags & CPU_DTRACE_FAULT) return; if (pcstack_limit <= 0) return; /* * If there's no user context we still need to zero the stack. */ if (p == NULL || (tf = curthread->td_frame) == NULL) goto zero; *pcstack++ = (uint64_t)p->p_pid; pcstack_limit--; if (pcstack_limit <= 0) return; pc = tf->srr0; sp = tf->fixreg[1]; if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { /* * In an entry probe. The frame pointer has not yet been * pushed (that happens in the function prologue). The * best approach is to add the current pc as a missing top * of stack and back the pc up to the caller, which is stored * at the current stack pointer address since the call * instruction puts it there right before the branch. */ *pcstack++ = (uint64_t)pc; pcstack_limit--; if (pcstack_limit <= 0) return; pc = tf->lr; } n = dtrace_getustack_common(pcstack, pcstack_limit, pc, sp); ASSERT(n >= 0); ASSERT(n <= pcstack_limit); pcstack += n; pcstack_limit -= n; zero: while (pcstack_limit-- > 0) *pcstack++ = 0; } int dtrace_getustackdepth(void) { proc_t *p = curproc; struct trapframe *tf; uintptr_t pc, sp; int n = 0; if (p == NULL || (tf = curthread->td_frame) == NULL) return (0); if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) return (-1); pc = tf->srr0; sp = tf->fixreg[1]; if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { /* * In an entry probe. The frame pointer has not yet been * pushed (that happens in the function prologue). The * best approach is to add the current pc as a missing top * of stack and back the pc up to the caller, which is stored * at the current stack pointer address since the call * instruction puts it there right before the branch. */ if (SV_PROC_FLAG(p, SV_ILP32)) { pc = dtrace_fuword32((void *) sp); } else pc = dtrace_fuword64((void *) sp); n++; } n += dtrace_getustack_common(NULL, 0, pc, sp); return (n); } void dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) { proc_t *p = curproc; struct trapframe *tf; uintptr_t pc, sp; volatile uint16_t *flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; #ifdef notyet /* XXX signal stack */ uintptr_t oldcontext; size_t s1, s2; #endif if (*flags & CPU_DTRACE_FAULT) return; if (pcstack_limit <= 0) return; /* * If there's no user context we still need to zero the stack. */ if (p == NULL || (tf = curthread->td_frame) == NULL) goto zero; *pcstack++ = (uint64_t)p->p_pid; pcstack_limit--; if (pcstack_limit <= 0) return; pc = tf->srr0; sp = tf->fixreg[1]; #ifdef notyet /* XXX signal stack */ oldcontext = lwp->lwp_oldcontext; s1 = sizeof (struct xframe) + 2 * sizeof (long); s2 = s1 + sizeof (siginfo_t); #endif if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { *pcstack++ = (uint64_t)pc; *fpstack++ = 0; pcstack_limit--; if (pcstack_limit <= 0) return; if (SV_PROC_FLAG(p, SV_ILP32)) { pc = dtrace_fuword32((void *)sp); } else { pc = dtrace_fuword64((void *)sp); } } while (pc != 0) { *pcstack++ = (uint64_t)pc; *fpstack++ = sp; pcstack_limit--; if (pcstack_limit <= 0) break; if (sp == 0) break; #ifdef notyet /* XXX signal stack */ if (oldcontext == sp + s1 || oldcontext == sp + s2) { ucontext_t *ucp = (ucontext_t *)oldcontext; greg_t *gregs = ucp->uc_mcontext.gregs; sp = dtrace_fulword(&gregs[REG_FP]); pc = dtrace_fulword(&gregs[REG_PC]); oldcontext = dtrace_fulword(&ucp->uc_link); } else #endif /* XXX */ { if (SV_PROC_FLAG(p, SV_ILP32)) { pc = dtrace_fuword32((void *)(sp + RETURN_OFFSET)); sp = dtrace_fuword32((void *)sp); } else { pc = dtrace_fuword64((void *)(sp + RETURN_OFFSET64)); sp = dtrace_fuword64((void *)sp); } } /* * This is totally bogus: if we faulted, we're going to clear * the fault and break. This is to deal with the apparently * broken Java stacks on x86. */ if (*flags & CPU_DTRACE_FAULT) { *flags &= ~CPU_DTRACE_FAULT; break; } } zero: while (pcstack_limit-- > 0) *pcstack++ = 0; } /*ARGSUSED*/ uint64_t dtrace_getarg(int arg, int aframes) { uintptr_t val; uintptr_t *fp = (uintptr_t *)__builtin_frame_address(0); uintptr_t *stack; int i; /* * A total of 8 arguments are passed via registers; any argument with * index of 7 or lower is therefore in a register. */ int inreg = 7; for (i = 1; i <= aframes; i++) { fp = (uintptr_t *)*fp; /* * On ppc32 trapexit() is the immediately following label. On * ppc64 AIM trapexit() follows a nop. */ #ifdef __powerpc64__ if ((long)(fp[2]) + 4 == (long)trapexit) { #else if ((long)(fp[1]) == (long)trapexit) { #endif /* * In the case of powerpc, we will use the pointer to the regs * structure that was pushed when we took the trap. To get this * structure, we must increment beyond the frame structure. If the * argument that we're seeking is passed on the stack, we'll pull * the true stack pointer out of the saved registers and decrement * our argument by the number of arguments passed in registers; if * the argument we're seeking is passed in regsiters, we can just * load it directly. */ #ifdef __powerpc64__ struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 48); #else struct reg *rp = (struct reg *)((uintptr_t)fp[0] + 8); #endif if (arg <= inreg) { stack = &rp->fixreg[3]; } else { stack = (uintptr_t *)(rp->fixreg[1]); arg -= inreg; } goto load; } } /* * We know that we did not come through a trap to get into * dtrace_probe() -- the provider simply called dtrace_probe() * directly. As this is the case, we need to shift the argument * that we're looking for: the probe ID is the first argument to * dtrace_probe(), so the argument n will actually be found where * one would expect to find argument (n + 1). */ arg++; if (arg <= inreg) { /* * This shouldn't happen. If the argument is passed in a * register then it should have been, well, passed in a * register... */ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); return (0); } arg -= (inreg + 1); stack = fp + 2; load: DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); val = stack[arg]; DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); return (val); } int dtrace_getstackdepth(int aframes) { int depth = 0; uintptr_t osp, sp; vm_offset_t callpc; osp = PAGE_SIZE; sp = (uintptr_t)__builtin_frame_address(0); for(;;) { if (sp <= osp) break; if (!dtrace_sp_inkernel(sp)) break; depth++; osp = sp; dtrace_next_sp_pc(sp, &sp, NULL, NULL); } if (depth < aframes) return (0); return (depth - aframes); } ulong_t -dtrace_getreg(struct trapframe *rp, uint_t reg) +dtrace_getreg(struct trapframe *frame, uint_t reg) { if (reg < 32) - return (rp->fixreg[reg]); + return (frame->fixreg[reg]); switch (reg) { case 32: - return (rp->lr); + return (frame->lr); case 33: - return (rp->cr); + return (frame->cr); case 34: - return (rp->xer); + return (frame->xer); case 35: - return (rp->ctr); + return (frame->ctr); case 36: - return (rp->srr0); + return (frame->srr0); case 37: - return (rp->srr1); + return (frame->srr1); case 38: - return (rp->exc); + return (frame->exc); default: DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); return (0); } } static int dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) { ASSERT(INKERNEL(kaddr) && kaddr + size >= kaddr); if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = uaddr; return (0); } return (1); } void dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, volatile uint16_t *flags) { if (dtrace_copycheck(uaddr, kaddr, size)) if (copyin((const void *)uaddr, (void *)kaddr, size)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; } } void dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, volatile uint16_t *flags) { if (dtrace_copycheck(uaddr, kaddr, size)) { if (copyout((const void *)kaddr, (void *)uaddr, size)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; } } } void dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, volatile uint16_t *flags) { size_t actual; int error; if (dtrace_copycheck(uaddr, kaddr, size)) { error = copyinstr((const void *)uaddr, (void *)kaddr, size, &actual); /* ENAMETOOLONG is not a fault condition. */ if (error && error != ENAMETOOLONG) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; } } } /* * The bulk of this function could be replaced to match dtrace_copyinstr() * if we ever implement a copyoutstr(). */ void dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, volatile uint16_t *flags) { size_t len; if (dtrace_copycheck(uaddr, kaddr, size)) { len = strlen((const char *)kaddr); if (len > size) len = size; if (copyout((const void *)kaddr, (void *)uaddr, len)) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; } } } uint8_t dtrace_fuword8(void *uaddr) { if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (fubyte(uaddr)); } uint16_t dtrace_fuword16(void *uaddr) { uint16_t ret = 0; if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) { if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; } } return ret; } uint32_t dtrace_fuword32(void *uaddr) { if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (fuword32(uaddr)); } uint64_t dtrace_fuword64(void *uaddr) { uint64_t ret = 0; if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) { if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; } } return ret; } uintptr_t dtrace_fulword(void *uaddr) { uintptr_t ret = 0; if (dtrace_copycheck((uintptr_t)uaddr, (uintptr_t)&ret, sizeof(ret))) { if (copyin((const void *)uaddr, (void *)&ret, sizeof(ret))) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; } } return ret; } diff --git a/sys/cddl/dev/dtrace/riscv/dtrace_isa.c b/sys/cddl/dev/dtrace/riscv/dtrace_isa.c index 61743c42d9b7..666f754cc311 100644 --- a/sys/cddl/dev/dtrace/riscv/dtrace_isa.c +++ b/sys/cddl/dev/dtrace/riscv/dtrace_isa.c @@ -1,443 +1,443 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Portions Copyright 2016 Ruslan Bukin * * $FreeBSD$ */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "regset.h" #define MAX_USTACK_DEPTH 2048 uint8_t dtrace_fuword8_nocheck(void *); uint16_t dtrace_fuword16_nocheck(void *); uint32_t dtrace_fuword32_nocheck(void *); uint64_t dtrace_fuword64_nocheck(void *); void dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, uint32_t *intrpc) { struct unwind_state state; uintptr_t caller; register_t sp; int scp_offset; int depth; depth = 0; caller = solaris_cpu[curcpu].cpu_dtrace_caller; if (intrpc != 0) { pcstack[depth++] = (pc_t)intrpc; } /* * Construct the unwind state, starting from this function. This frame, * and 'aframes' others will be skipped. */ __asm __volatile("mv %0, sp" : "=&r" (sp)); state.fp = (uintptr_t)__builtin_frame_address(0); state.sp = (uintptr_t)sp; state.pc = (uintptr_t)dtrace_getpcstack; while (depth < pcstack_limit) { if (!unwind_frame(curthread, &state)) break; if (!INKERNEL(state.pc) || !kstack_contains(curthread, (vm_offset_t)state.fp, sizeof(uintptr_t))) break; if (aframes > 0) { aframes--; /* * fbt_invop() records the return address at the time * the FBT probe fires. We need to insert this into the * backtrace manually, since the stack frame state at * the time of the probe does not capture it. */ if (aframes == 0 && caller != 0) pcstack[depth++] = caller; } else { pcstack[depth++] = state.pc; } } for (; depth < pcstack_limit; depth++) { pcstack[depth] = 0; } } static int dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, uintptr_t fp) { volatile uint16_t *flags; uintptr_t oldfp; int ret; oldfp = fp; ret = 0; flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; ASSERT(pcstack == NULL || pcstack_limit > 0); while (pc != 0) { /* * We limit the number of times we can go around this * loop to account for a circular stack. */ if (ret++ >= MAX_USTACK_DEPTH) { *flags |= CPU_DTRACE_BADSTACK; cpu_core[curcpu].cpuc_dtrace_illval = fp; break; } if (pcstack != NULL) { *pcstack++ = (uint64_t)pc; pcstack_limit--; if (pcstack_limit <= 0) break; } if (fp == 0) break; pc = dtrace_fuword64((void *)(fp - 1 * sizeof(uint64_t))); fp = dtrace_fuword64((void *)(fp - 2 * sizeof(uint64_t))); if (fp == oldfp) { *flags |= CPU_DTRACE_BADSTACK; cpu_core[curcpu].cpuc_dtrace_illval = fp; break; } oldfp = fp; } return (ret); } void dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) { volatile uint16_t *flags; struct trapframe *tf; uintptr_t pc, fp; proc_t *p; int n; p = curproc; flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; if (*flags & CPU_DTRACE_FAULT) return; if (pcstack_limit <= 0) return; /* * If there's no user context we still need to zero the stack. */ if (p == NULL || (tf = curthread->td_frame) == NULL) goto zero; *pcstack++ = (uint64_t)p->p_pid; pcstack_limit--; if (pcstack_limit <= 0) return; pc = tf->tf_sepc; fp = tf->tf_s[0]; if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { /* * In an entry probe. The frame pointer has not yet been * pushed (that happens in the function prologue). The * best approach is to add the current pc as a missing top * of stack and back the pc up to the caller, which is stored * at the current stack pointer address since the call * instruction puts it there right before the branch. */ *pcstack++ = (uint64_t)pc; pcstack_limit--; if (pcstack_limit <= 0) return; pc = tf->tf_ra; } n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp); ASSERT(n >= 0); ASSERT(n <= pcstack_limit); pcstack += n; pcstack_limit -= n; zero: while (pcstack_limit-- > 0) *pcstack++ = 0; } int dtrace_getustackdepth(void) { struct trapframe *tf; uintptr_t pc, fp; int n = 0; if (curproc == NULL || (tf = curthread->td_frame) == NULL) return (0); if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) return (-1); pc = tf->tf_sepc; fp = tf->tf_s[0]; if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { /* * In an entry probe. The frame pointer has not yet been * pushed (that happens in the function prologue). The * best approach is to add the current pc as a missing top * of stack and back the pc up to the caller, which is stored * at the current stack pointer address since the call * instruction puts it there right before the branch. */ pc = tf->tf_ra; n++; } n += dtrace_getustack_common(NULL, 0, pc, fp); return (0); } void dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) { printf("IMPLEMENT ME: %s\n", __func__); } /*ARGSUSED*/ uint64_t dtrace_getarg(int arg, int aframes) { printf("IMPLEMENT ME: %s\n", __func__); return (0); } int dtrace_getstackdepth(int aframes) { struct unwind_state state; int scp_offset; register_t sp; int depth; bool done; depth = 1; done = false; __asm __volatile("mv %0, sp" : "=&r" (sp)); state.fp = (uintptr_t)__builtin_frame_address(0); state.sp = sp; state.pc = (uintptr_t)dtrace_getstackdepth; do { done = !unwind_frame(curthread, &state); if (!INKERNEL(state.pc) || !INKERNEL(state.fp)) break; depth++; } while (!done); if (depth < aframes) return (0); else return (depth - aframes); } ulong_t -dtrace_getreg(struct trapframe *rp, uint_t reg) +dtrace_getreg(struct trapframe *frame, uint_t reg) { switch (reg) { case REG_ZERO: return (0); case REG_RA: - return (rp->tf_ra); + return (frame->tf_ra); case REG_SP: - return (rp->tf_sp); + return (frame->tf_sp); case REG_GP: - return (rp->tf_gp); + return (frame->tf_gp); case REG_TP: - return (rp->tf_tp); + return (frame->tf_tp); case REG_T0 ... REG_T2: - return (rp->tf_t[reg - REG_T0]); + return (frame->tf_t[reg - REG_T0]); case REG_S0 ... REG_S1: - return (rp->tf_s[reg - REG_S0]); + return (frame->tf_s[reg - REG_S0]); case REG_A0 ... REG_A7: - return (rp->tf_a[reg - REG_A0]); + return (frame->tf_a[reg - REG_A0]); case REG_S2 ... REG_S11: - return (rp->tf_s[reg - REG_S2 + 2]); + return (frame->tf_s[reg - REG_S2 + 2]); case REG_T3 ... REG_T6: - return (rp->tf_t[reg - REG_T3 + 3]); + return (frame->tf_t[reg - REG_T3 + 3]); case REG_PC: - return (rp->tf_sepc); + return (frame->tf_sepc); default: DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); return (0); } /* NOTREACHED */ } static int dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) { if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = uaddr; return (0); } return (1); } void dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, volatile uint16_t *flags) { if (dtrace_copycheck(uaddr, kaddr, size)) dtrace_copy(uaddr, kaddr, size); } void dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, volatile uint16_t *flags) { if (dtrace_copycheck(uaddr, kaddr, size)) dtrace_copy(kaddr, uaddr, size); } void dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, volatile uint16_t *flags) { if (dtrace_copycheck(uaddr, kaddr, size)) dtrace_copystr(uaddr, kaddr, size, flags); } void dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, volatile uint16_t *flags) { if (dtrace_copycheck(uaddr, kaddr, size)) dtrace_copystr(kaddr, uaddr, size, flags); } uint8_t dtrace_fuword8(void *uaddr) { if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword8_nocheck(uaddr)); } uint16_t dtrace_fuword16(void *uaddr) { if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword16_nocheck(uaddr)); } uint32_t dtrace_fuword32(void *uaddr) { if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword32_nocheck(uaddr)); } uint64_t dtrace_fuword64(void *uaddr) { if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; return (0); } return (dtrace_fuword64_nocheck(uaddr)); }