1fed1ca4bSRuslan Bukin /* 2fed1ca4bSRuslan Bukin * CDDL HEADER START 3fed1ca4bSRuslan Bukin * 4fed1ca4bSRuslan Bukin * The contents of this file are subject to the terms of the 5fed1ca4bSRuslan Bukin * Common Development and Distribution License, Version 1.0 only 6fed1ca4bSRuslan Bukin * (the "License"). You may not use this file except in compliance 7fed1ca4bSRuslan Bukin * with the License. 8fed1ca4bSRuslan Bukin * 9fed1ca4bSRuslan Bukin * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10fed1ca4bSRuslan Bukin * or http://www.opensolaris.org/os/licensing. 11fed1ca4bSRuslan Bukin * See the License for the specific language governing permissions 12fed1ca4bSRuslan Bukin * and limitations under the License. 13fed1ca4bSRuslan Bukin * 14fed1ca4bSRuslan Bukin * When distributing Covered Code, include this CDDL HEADER in each 15fed1ca4bSRuslan Bukin * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16fed1ca4bSRuslan Bukin * If applicable, add the following below this CDDL HEADER, with the 17fed1ca4bSRuslan Bukin * fields enclosed by brackets "[]" replaced with your own identifying 18fed1ca4bSRuslan Bukin * information: Portions Copyright [yyyy] [name of copyright owner] 19fed1ca4bSRuslan Bukin * 20fed1ca4bSRuslan Bukin * CDDL HEADER END 21fed1ca4bSRuslan Bukin * 22fed1ca4bSRuslan Bukin * Portions Copyright 2016 Ruslan Bukin <br@bsdpad.com> 23fed1ca4bSRuslan Bukin */ 24fed1ca4bSRuslan Bukin /* 25fed1ca4bSRuslan Bukin * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 26fed1ca4bSRuslan Bukin * Use is subject to license terms. 27fed1ca4bSRuslan Bukin */ 28fed1ca4bSRuslan Bukin #include <sys/cdefs.h> 29fed1ca4bSRuslan Bukin 30fed1ca4bSRuslan Bukin #include <sys/param.h> 31fed1ca4bSRuslan Bukin #include <sys/systm.h> 32*82283cadSMark Johnston #include <sys/dtrace_impl.h> 33fed1ca4bSRuslan Bukin #include <sys/kernel.h> 34fed1ca4bSRuslan Bukin #include <sys/stack.h> 35fed1ca4bSRuslan Bukin #include <sys/pcpu.h> 36fed1ca4bSRuslan Bukin 37fed1ca4bSRuslan Bukin #include <machine/frame.h> 38fed1ca4bSRuslan Bukin #include <machine/md_var.h> 397a8cf053SChristos Margiolis #include <machine/encoding.h> 407a8cf053SChristos Margiolis #include <machine/riscvreg.h> 41fed1ca4bSRuslan Bukin 42fed1ca4bSRuslan Bukin #include <vm/vm.h> 43fed1ca4bSRuslan Bukin #include <vm/vm_param.h> 44fed1ca4bSRuslan Bukin #include <vm/pmap.h> 45fed1ca4bSRuslan Bukin 46fed1ca4bSRuslan Bukin #include <machine/atomic.h> 47fed1ca4bSRuslan Bukin #include <machine/db_machdep.h> 48fed1ca4bSRuslan Bukin #include <machine/md_var.h> 49fed1ca4bSRuslan Bukin #include <machine/stack.h> 50fed1ca4bSRuslan Bukin #include <ddb/db_sym.h> 51fed1ca4bSRuslan Bukin #include <ddb/ddb.h> 52fed1ca4bSRuslan Bukin #include <sys/kdb.h> 53fed1ca4bSRuslan Bukin 54fed1ca4bSRuslan Bukin #include "regset.h" 55fed1ca4bSRuslan Bukin 56fed1ca4bSRuslan Bukin #define MAX_USTACK_DEPTH 2048 57fed1ca4bSRuslan Bukin 58fed1ca4bSRuslan Bukin uint8_t dtrace_fuword8_nocheck(void *); 59fed1ca4bSRuslan Bukin uint16_t dtrace_fuword16_nocheck(void *); 60fed1ca4bSRuslan Bukin uint32_t dtrace_fuword32_nocheck(void *); 61fed1ca4bSRuslan Bukin uint64_t dtrace_fuword64_nocheck(void *); 62fed1ca4bSRuslan Bukin 637a8cf053SChristos Margiolis int dtrace_match_opcode(uint32_t, int, int); 647a8cf053SChristos Margiolis int dtrace_instr_sdsp(uint32_t **); 657a8cf053SChristos Margiolis int dtrace_instr_ret(uint32_t **); 667a8cf053SChristos Margiolis int dtrace_instr_c_sdsp(uint32_t **); 677a8cf053SChristos Margiolis int dtrace_instr_c_ret(uint32_t **); 687a8cf053SChristos Margiolis 69fed1ca4bSRuslan Bukin void 70fed1ca4bSRuslan Bukin dtrace_getpcstack(pc_t *pcstack, int pcstack_limit, int aframes, 71fed1ca4bSRuslan Bukin uint32_t *intrpc) 72fed1ca4bSRuslan Bukin { 73fed1ca4bSRuslan Bukin struct unwind_state state; 74cdfa49f2SMitchell Horne uintptr_t caller; 75fed1ca4bSRuslan Bukin register_t sp; 76cdfa49f2SMitchell Horne int scp_offset; 77fed1ca4bSRuslan Bukin int depth; 78fed1ca4bSRuslan Bukin 79fed1ca4bSRuslan Bukin depth = 0; 80cdfa49f2SMitchell Horne caller = solaris_cpu[curcpu].cpu_dtrace_caller; 81fed1ca4bSRuslan Bukin 82fed1ca4bSRuslan Bukin if (intrpc != 0) { 83fed1ca4bSRuslan Bukin pcstack[depth++] = (pc_t)intrpc; 84fed1ca4bSRuslan Bukin } 85fed1ca4bSRuslan Bukin 86cdfa49f2SMitchell Horne /* 87cdfa49f2SMitchell Horne * Construct the unwind state, starting from this function. This frame, 88cdfa49f2SMitchell Horne * and 'aframes' others will be skipped. 89cdfa49f2SMitchell Horne */ 90fed1ca4bSRuslan Bukin __asm __volatile("mv %0, sp" : "=&r" (sp)); 91fed1ca4bSRuslan Bukin 92fdd947e4SJohn Baldwin state.fp = (uintptr_t)__builtin_frame_address(0); 93cdfa49f2SMitchell Horne state.sp = (uintptr_t)sp; 94fdd947e4SJohn Baldwin state.pc = (uintptr_t)dtrace_getpcstack; 95fed1ca4bSRuslan Bukin 96fed1ca4bSRuslan Bukin while (depth < pcstack_limit) { 979b9e7f4cSJohn Baldwin if (!unwind_frame(curthread, &state)) 98fed1ca4bSRuslan Bukin break; 99fed1ca4bSRuslan Bukin 100cdfa49f2SMitchell Horne if (!INKERNEL(state.pc) || !kstack_contains(curthread, 101cdfa49f2SMitchell Horne (vm_offset_t)state.fp, sizeof(uintptr_t))) 102fed1ca4bSRuslan Bukin break; 103fed1ca4bSRuslan Bukin 104fed1ca4bSRuslan Bukin if (aframes > 0) { 105fed1ca4bSRuslan Bukin aframes--; 106cdfa49f2SMitchell Horne 107cdfa49f2SMitchell Horne /* 108cdfa49f2SMitchell Horne * fbt_invop() records the return address at the time 109cdfa49f2SMitchell Horne * the FBT probe fires. We need to insert this into the 110cdfa49f2SMitchell Horne * backtrace manually, since the stack frame state at 111cdfa49f2SMitchell Horne * the time of the probe does not capture it. 112cdfa49f2SMitchell Horne */ 113cdfa49f2SMitchell Horne if (aframes == 0 && caller != 0) 114cdfa49f2SMitchell Horne pcstack[depth++] = caller; 115fed1ca4bSRuslan Bukin } else { 116fed1ca4bSRuslan Bukin pcstack[depth++] = state.pc; 117fed1ca4bSRuslan Bukin } 118fed1ca4bSRuslan Bukin } 119fed1ca4bSRuslan Bukin 120fed1ca4bSRuslan Bukin for (; depth < pcstack_limit; depth++) { 121fed1ca4bSRuslan Bukin pcstack[depth] = 0; 122fed1ca4bSRuslan Bukin } 123fed1ca4bSRuslan Bukin } 124fed1ca4bSRuslan Bukin 125fed1ca4bSRuslan Bukin static int 126fed1ca4bSRuslan Bukin dtrace_getustack_common(uint64_t *pcstack, int pcstack_limit, uintptr_t pc, 127fed1ca4bSRuslan Bukin uintptr_t fp) 128fed1ca4bSRuslan Bukin { 129fed1ca4bSRuslan Bukin volatile uint16_t *flags; 130fed1ca4bSRuslan Bukin uintptr_t oldfp; 131fed1ca4bSRuslan Bukin int ret; 132fed1ca4bSRuslan Bukin 1330b92d1ddSMitchell Horne oldfp = fp; 134fed1ca4bSRuslan Bukin ret = 0; 135fed1ca4bSRuslan Bukin flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 136fed1ca4bSRuslan Bukin 137fed1ca4bSRuslan Bukin ASSERT(pcstack == NULL || pcstack_limit > 0); 138fed1ca4bSRuslan Bukin 139fed1ca4bSRuslan Bukin while (pc != 0) { 140fed1ca4bSRuslan Bukin /* 141fed1ca4bSRuslan Bukin * We limit the number of times we can go around this 142fed1ca4bSRuslan Bukin * loop to account for a circular stack. 143fed1ca4bSRuslan Bukin */ 144fed1ca4bSRuslan Bukin if (ret++ >= MAX_USTACK_DEPTH) { 145fed1ca4bSRuslan Bukin *flags |= CPU_DTRACE_BADSTACK; 146fed1ca4bSRuslan Bukin cpu_core[curcpu].cpuc_dtrace_illval = fp; 147fed1ca4bSRuslan Bukin break; 148fed1ca4bSRuslan Bukin } 149fed1ca4bSRuslan Bukin 150fed1ca4bSRuslan Bukin if (pcstack != NULL) { 151fed1ca4bSRuslan Bukin *pcstack++ = (uint64_t)pc; 152fed1ca4bSRuslan Bukin pcstack_limit--; 153fed1ca4bSRuslan Bukin if (pcstack_limit <= 0) 154fed1ca4bSRuslan Bukin break; 155fed1ca4bSRuslan Bukin } 156fed1ca4bSRuslan Bukin 157fed1ca4bSRuslan Bukin if (fp == 0) 158fed1ca4bSRuslan Bukin break; 159fed1ca4bSRuslan Bukin 16038720107SJessica Clarke pc = dtrace_fuword64((void *)(fp - 1 * sizeof(uint64_t))); 16138720107SJessica Clarke fp = dtrace_fuword64((void *)(fp - 2 * sizeof(uint64_t))); 162fed1ca4bSRuslan Bukin 163fed1ca4bSRuslan Bukin if (fp == oldfp) { 164fed1ca4bSRuslan Bukin *flags |= CPU_DTRACE_BADSTACK; 165fed1ca4bSRuslan Bukin cpu_core[curcpu].cpuc_dtrace_illval = fp; 166fed1ca4bSRuslan Bukin break; 167fed1ca4bSRuslan Bukin } 1680b92d1ddSMitchell Horne oldfp = fp; 169fed1ca4bSRuslan Bukin } 170fed1ca4bSRuslan Bukin 171fed1ca4bSRuslan Bukin return (ret); 172fed1ca4bSRuslan Bukin } 173fed1ca4bSRuslan Bukin 174fed1ca4bSRuslan Bukin void 175fed1ca4bSRuslan Bukin dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit) 176fed1ca4bSRuslan Bukin { 177fed1ca4bSRuslan Bukin volatile uint16_t *flags; 178fed1ca4bSRuslan Bukin struct trapframe *tf; 179c6943b44SMitchell Horne uintptr_t pc, fp; 180fed1ca4bSRuslan Bukin proc_t *p; 181fed1ca4bSRuslan Bukin int n; 182fed1ca4bSRuslan Bukin 183fed1ca4bSRuslan Bukin p = curproc; 184fed1ca4bSRuslan Bukin flags = (volatile uint16_t *)&cpu_core[curcpu].cpuc_dtrace_flags; 185fed1ca4bSRuslan Bukin 186fed1ca4bSRuslan Bukin if (*flags & CPU_DTRACE_FAULT) 187fed1ca4bSRuslan Bukin return; 188fed1ca4bSRuslan Bukin 189fed1ca4bSRuslan Bukin if (pcstack_limit <= 0) 190fed1ca4bSRuslan Bukin return; 191fed1ca4bSRuslan Bukin 192fed1ca4bSRuslan Bukin /* 193fed1ca4bSRuslan Bukin * If there's no user context we still need to zero the stack. 194fed1ca4bSRuslan Bukin */ 195fed1ca4bSRuslan Bukin if (p == NULL || (tf = curthread->td_frame) == NULL) 196fed1ca4bSRuslan Bukin goto zero; 197fed1ca4bSRuslan Bukin 198fed1ca4bSRuslan Bukin *pcstack++ = (uint64_t)p->p_pid; 199fed1ca4bSRuslan Bukin pcstack_limit--; 200fed1ca4bSRuslan Bukin 201fed1ca4bSRuslan Bukin if (pcstack_limit <= 0) 202fed1ca4bSRuslan Bukin return; 203fed1ca4bSRuslan Bukin 204fed1ca4bSRuslan Bukin pc = tf->tf_sepc; 205fed1ca4bSRuslan Bukin fp = tf->tf_s[0]; 206fed1ca4bSRuslan Bukin 207fed1ca4bSRuslan Bukin if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 208fed1ca4bSRuslan Bukin /* 209fed1ca4bSRuslan Bukin * In an entry probe. The frame pointer has not yet been 210fed1ca4bSRuslan Bukin * pushed (that happens in the function prologue). The 211fed1ca4bSRuslan Bukin * best approach is to add the current pc as a missing top 212fed1ca4bSRuslan Bukin * of stack and back the pc up to the caller, which is stored 213fed1ca4bSRuslan Bukin * at the current stack pointer address since the call 214fed1ca4bSRuslan Bukin * instruction puts it there right before the branch. 215fed1ca4bSRuslan Bukin */ 216fed1ca4bSRuslan Bukin *pcstack++ = (uint64_t)pc; 217fed1ca4bSRuslan Bukin pcstack_limit--; 218fed1ca4bSRuslan Bukin if (pcstack_limit <= 0) 219fed1ca4bSRuslan Bukin return; 220fed1ca4bSRuslan Bukin 221fed1ca4bSRuslan Bukin pc = tf->tf_ra; 222fed1ca4bSRuslan Bukin } 223fed1ca4bSRuslan Bukin 224fed1ca4bSRuslan Bukin n = dtrace_getustack_common(pcstack, pcstack_limit, pc, fp); 225fed1ca4bSRuslan Bukin ASSERT(n >= 0); 226fed1ca4bSRuslan Bukin ASSERT(n <= pcstack_limit); 227fed1ca4bSRuslan Bukin 228fed1ca4bSRuslan Bukin pcstack += n; 229fed1ca4bSRuslan Bukin pcstack_limit -= n; 230fed1ca4bSRuslan Bukin 231fed1ca4bSRuslan Bukin zero: 232fed1ca4bSRuslan Bukin while (pcstack_limit-- > 0) 233fed1ca4bSRuslan Bukin *pcstack++ = 0; 234fed1ca4bSRuslan Bukin } 235fed1ca4bSRuslan Bukin 236fed1ca4bSRuslan Bukin int 237fed1ca4bSRuslan Bukin dtrace_getustackdepth(void) 238fed1ca4bSRuslan Bukin { 239c6943b44SMitchell Horne struct trapframe *tf; 240c6943b44SMitchell Horne uintptr_t pc, fp; 241c6943b44SMitchell Horne int n = 0; 242fed1ca4bSRuslan Bukin 243c6943b44SMitchell Horne if (curproc == NULL || (tf = curthread->td_frame) == NULL) 244c6943b44SMitchell Horne return (0); 245c6943b44SMitchell Horne 246c6943b44SMitchell Horne if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_FAULT)) 247c6943b44SMitchell Horne return (-1); 248c6943b44SMitchell Horne 249c6943b44SMitchell Horne pc = tf->tf_sepc; 250c6943b44SMitchell Horne fp = tf->tf_s[0]; 251c6943b44SMitchell Horne 252c6943b44SMitchell Horne if (DTRACE_CPUFLAG_ISSET(CPU_DTRACE_ENTRY)) { 253c6943b44SMitchell Horne /* 254c6943b44SMitchell Horne * In an entry probe. The frame pointer has not yet been 255c6943b44SMitchell Horne * pushed (that happens in the function prologue). The 256c6943b44SMitchell Horne * best approach is to add the current pc as a missing top 257c6943b44SMitchell Horne * of stack and back the pc up to the caller, which is stored 258c6943b44SMitchell Horne * at the current stack pointer address since the call 259c6943b44SMitchell Horne * instruction puts it there right before the branch. 260c6943b44SMitchell Horne */ 261c6943b44SMitchell Horne pc = tf->tf_ra; 262c6943b44SMitchell Horne n++; 263c6943b44SMitchell Horne } 264c6943b44SMitchell Horne 265c6943b44SMitchell Horne n += dtrace_getustack_common(NULL, 0, pc, fp); 266fed1ca4bSRuslan Bukin 267fed1ca4bSRuslan Bukin return (0); 268fed1ca4bSRuslan Bukin } 269fed1ca4bSRuslan Bukin 270fed1ca4bSRuslan Bukin void 271fed1ca4bSRuslan Bukin dtrace_getufpstack(uint64_t *pcstack, uint64_t *fpstack, int pcstack_limit) 272fed1ca4bSRuslan Bukin { 273fed1ca4bSRuslan Bukin 274fed1ca4bSRuslan Bukin printf("IMPLEMENT ME: %s\n", __func__); 275fed1ca4bSRuslan Bukin } 276fed1ca4bSRuslan Bukin 277fed1ca4bSRuslan Bukin /*ARGSUSED*/ 278fed1ca4bSRuslan Bukin uint64_t 279fed1ca4bSRuslan Bukin dtrace_getarg(int arg, int aframes) 280fed1ca4bSRuslan Bukin { 281fed1ca4bSRuslan Bukin 282fed1ca4bSRuslan Bukin printf("IMPLEMENT ME: %s\n", __func__); 283fed1ca4bSRuslan Bukin 284fed1ca4bSRuslan Bukin return (0); 285fed1ca4bSRuslan Bukin } 286fed1ca4bSRuslan Bukin 287fed1ca4bSRuslan Bukin int 288fed1ca4bSRuslan Bukin dtrace_getstackdepth(int aframes) 289fed1ca4bSRuslan Bukin { 290fed1ca4bSRuslan Bukin struct unwind_state state; 291fed1ca4bSRuslan Bukin int scp_offset; 292fed1ca4bSRuslan Bukin register_t sp; 293fed1ca4bSRuslan Bukin int depth; 2949b9e7f4cSJohn Baldwin bool done; 295fed1ca4bSRuslan Bukin 296fed1ca4bSRuslan Bukin depth = 1; 2979b9e7f4cSJohn Baldwin done = false; 298fed1ca4bSRuslan Bukin 299fed1ca4bSRuslan Bukin __asm __volatile("mv %0, sp" : "=&r" (sp)); 300fed1ca4bSRuslan Bukin 301fdd947e4SJohn Baldwin state.fp = (uintptr_t)__builtin_frame_address(0); 302fed1ca4bSRuslan Bukin state.sp = sp; 303fdd947e4SJohn Baldwin state.pc = (uintptr_t)dtrace_getstackdepth; 304fed1ca4bSRuslan Bukin 305fed1ca4bSRuslan Bukin do { 3069b9e7f4cSJohn Baldwin done = !unwind_frame(curthread, &state); 307fed1ca4bSRuslan Bukin if (!INKERNEL(state.pc) || !INKERNEL(state.fp)) 308fed1ca4bSRuslan Bukin break; 309fed1ca4bSRuslan Bukin depth++; 310fed1ca4bSRuslan Bukin } while (!done); 311fed1ca4bSRuslan Bukin 312fed1ca4bSRuslan Bukin if (depth < aframes) 313fed1ca4bSRuslan Bukin return (0); 314fed1ca4bSRuslan Bukin else 315fed1ca4bSRuslan Bukin return (depth - aframes); 316fed1ca4bSRuslan Bukin } 317fed1ca4bSRuslan Bukin 318fed1ca4bSRuslan Bukin ulong_t 31998ab9802SChristos Margiolis dtrace_getreg(struct trapframe *frame, uint_t reg) 320fed1ca4bSRuslan Bukin { 3211fef7abdSChristos Margiolis switch (reg) { 3221fef7abdSChristos Margiolis case REG_ZERO: 323fed1ca4bSRuslan Bukin return (0); 3241fef7abdSChristos Margiolis case REG_RA: 32598ab9802SChristos Margiolis return (frame->tf_ra); 3261fef7abdSChristos Margiolis case REG_SP: 32798ab9802SChristos Margiolis return (frame->tf_sp); 3281fef7abdSChristos Margiolis case REG_GP: 32998ab9802SChristos Margiolis return (frame->tf_gp); 3301fef7abdSChristos Margiolis case REG_TP: 33198ab9802SChristos Margiolis return (frame->tf_tp); 3321fef7abdSChristos Margiolis case REG_T0 ... REG_T2: 33398ab9802SChristos Margiolis return (frame->tf_t[reg - REG_T0]); 3341fef7abdSChristos Margiolis case REG_S0 ... REG_S1: 33598ab9802SChristos Margiolis return (frame->tf_s[reg - REG_S0]); 3361fef7abdSChristos Margiolis case REG_A0 ... REG_A7: 33798ab9802SChristos Margiolis return (frame->tf_a[reg - REG_A0]); 3381fef7abdSChristos Margiolis case REG_S2 ... REG_S11: 33998ab9802SChristos Margiolis return (frame->tf_s[reg - REG_S2 + 2]); 3401fef7abdSChristos Margiolis case REG_T3 ... REG_T6: 34198ab9802SChristos Margiolis return (frame->tf_t[reg - REG_T3 + 3]); 3421fef7abdSChristos Margiolis case REG_PC: 34398ab9802SChristos Margiolis return (frame->tf_sepc); 3441fef7abdSChristos Margiolis default: 3451fef7abdSChristos Margiolis DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 3461fef7abdSChristos Margiolis return (0); 3471fef7abdSChristos Margiolis } 3481fef7abdSChristos Margiolis /* NOTREACHED */ 349fed1ca4bSRuslan Bukin } 350fed1ca4bSRuslan Bukin 351fed1ca4bSRuslan Bukin static int 352fed1ca4bSRuslan Bukin dtrace_copycheck(uintptr_t uaddr, uintptr_t kaddr, size_t size) 353fed1ca4bSRuslan Bukin { 354fed1ca4bSRuslan Bukin 355fed1ca4bSRuslan Bukin if (uaddr + size > VM_MAXUSER_ADDRESS || uaddr + size < uaddr) { 356fed1ca4bSRuslan Bukin DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 357fed1ca4bSRuslan Bukin cpu_core[curcpu].cpuc_dtrace_illval = uaddr; 358fed1ca4bSRuslan Bukin return (0); 359fed1ca4bSRuslan Bukin } 360fed1ca4bSRuslan Bukin 361fed1ca4bSRuslan Bukin return (1); 362fed1ca4bSRuslan Bukin } 363fed1ca4bSRuslan Bukin 364fed1ca4bSRuslan Bukin void 365fed1ca4bSRuslan Bukin dtrace_copyin(uintptr_t uaddr, uintptr_t kaddr, size_t size, 366fed1ca4bSRuslan Bukin volatile uint16_t *flags) 367fed1ca4bSRuslan Bukin { 368fed1ca4bSRuslan Bukin 369fed1ca4bSRuslan Bukin if (dtrace_copycheck(uaddr, kaddr, size)) 370fed1ca4bSRuslan Bukin dtrace_copy(uaddr, kaddr, size); 371fed1ca4bSRuslan Bukin } 372fed1ca4bSRuslan Bukin 373fed1ca4bSRuslan Bukin void 374fed1ca4bSRuslan Bukin dtrace_copyout(uintptr_t kaddr, uintptr_t uaddr, size_t size, 375fed1ca4bSRuslan Bukin volatile uint16_t *flags) 376fed1ca4bSRuslan Bukin { 377fed1ca4bSRuslan Bukin 378fed1ca4bSRuslan Bukin if (dtrace_copycheck(uaddr, kaddr, size)) 379fed1ca4bSRuslan Bukin dtrace_copy(kaddr, uaddr, size); 380fed1ca4bSRuslan Bukin } 381fed1ca4bSRuslan Bukin 382fed1ca4bSRuslan Bukin void 383fed1ca4bSRuslan Bukin dtrace_copyinstr(uintptr_t uaddr, uintptr_t kaddr, size_t size, 384fed1ca4bSRuslan Bukin volatile uint16_t *flags) 385fed1ca4bSRuslan Bukin { 386fed1ca4bSRuslan Bukin 387fed1ca4bSRuslan Bukin if (dtrace_copycheck(uaddr, kaddr, size)) 388fed1ca4bSRuslan Bukin dtrace_copystr(uaddr, kaddr, size, flags); 389fed1ca4bSRuslan Bukin } 390fed1ca4bSRuslan Bukin 391fed1ca4bSRuslan Bukin void 392fed1ca4bSRuslan Bukin dtrace_copyoutstr(uintptr_t kaddr, uintptr_t uaddr, size_t size, 393fed1ca4bSRuslan Bukin volatile uint16_t *flags) 394fed1ca4bSRuslan Bukin { 395fed1ca4bSRuslan Bukin 396fed1ca4bSRuslan Bukin if (dtrace_copycheck(uaddr, kaddr, size)) 397fed1ca4bSRuslan Bukin dtrace_copystr(kaddr, uaddr, size, flags); 398fed1ca4bSRuslan Bukin } 399fed1ca4bSRuslan Bukin 400fed1ca4bSRuslan Bukin uint8_t 401fed1ca4bSRuslan Bukin dtrace_fuword8(void *uaddr) 402fed1ca4bSRuslan Bukin { 403fed1ca4bSRuslan Bukin 404fed1ca4bSRuslan Bukin if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 405fed1ca4bSRuslan Bukin DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 406fed1ca4bSRuslan Bukin cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 407fed1ca4bSRuslan Bukin return (0); 408fed1ca4bSRuslan Bukin } 409fed1ca4bSRuslan Bukin 410fed1ca4bSRuslan Bukin return (dtrace_fuword8_nocheck(uaddr)); 411fed1ca4bSRuslan Bukin } 412fed1ca4bSRuslan Bukin 413fed1ca4bSRuslan Bukin uint16_t 414fed1ca4bSRuslan Bukin dtrace_fuword16(void *uaddr) 415fed1ca4bSRuslan Bukin { 416fed1ca4bSRuslan Bukin 417fed1ca4bSRuslan Bukin if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 418fed1ca4bSRuslan Bukin DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 419fed1ca4bSRuslan Bukin cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 420fed1ca4bSRuslan Bukin return (0); 421fed1ca4bSRuslan Bukin } 422fed1ca4bSRuslan Bukin 423fed1ca4bSRuslan Bukin return (dtrace_fuword16_nocheck(uaddr)); 424fed1ca4bSRuslan Bukin } 425fed1ca4bSRuslan Bukin 426fed1ca4bSRuslan Bukin uint32_t 427fed1ca4bSRuslan Bukin dtrace_fuword32(void *uaddr) 428fed1ca4bSRuslan Bukin { 429fed1ca4bSRuslan Bukin 430fed1ca4bSRuslan Bukin if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 431fed1ca4bSRuslan Bukin DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 432fed1ca4bSRuslan Bukin cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 433fed1ca4bSRuslan Bukin return (0); 434fed1ca4bSRuslan Bukin } 435fed1ca4bSRuslan Bukin 436fed1ca4bSRuslan Bukin return (dtrace_fuword32_nocheck(uaddr)); 437fed1ca4bSRuslan Bukin } 438fed1ca4bSRuslan Bukin 439fed1ca4bSRuslan Bukin uint64_t 440fed1ca4bSRuslan Bukin dtrace_fuword64(void *uaddr) 441fed1ca4bSRuslan Bukin { 442fed1ca4bSRuslan Bukin 443fed1ca4bSRuslan Bukin if ((uintptr_t)uaddr > VM_MAXUSER_ADDRESS) { 444fed1ca4bSRuslan Bukin DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR); 445fed1ca4bSRuslan Bukin cpu_core[curcpu].cpuc_dtrace_illval = (uintptr_t)uaddr; 446fed1ca4bSRuslan Bukin return (0); 447fed1ca4bSRuslan Bukin } 448fed1ca4bSRuslan Bukin 449fed1ca4bSRuslan Bukin return (dtrace_fuword64_nocheck(uaddr)); 450fed1ca4bSRuslan Bukin } 4517a8cf053SChristos Margiolis 4527a8cf053SChristos Margiolis int 4537a8cf053SChristos Margiolis dtrace_match_opcode(uint32_t insn, int match, int mask) 4547a8cf053SChristos Margiolis { 4557a8cf053SChristos Margiolis if (((insn ^ match) & mask) == 0) 4567a8cf053SChristos Margiolis return (1); 4577a8cf053SChristos Margiolis 4587a8cf053SChristos Margiolis return (0); 4597a8cf053SChristos Margiolis } 4607a8cf053SChristos Margiolis 4617a8cf053SChristos Margiolis int 4627a8cf053SChristos Margiolis dtrace_instr_sdsp(uint32_t **instr) 4637a8cf053SChristos Margiolis { 4647a8cf053SChristos Margiolis if (dtrace_match_opcode(**instr, (MATCH_SD | RS2_RA | RS1_SP), 4657a8cf053SChristos Margiolis (MASK_SD | RS2_MASK | RS1_MASK))) 4667a8cf053SChristos Margiolis return (1); 4677a8cf053SChristos Margiolis 4687a8cf053SChristos Margiolis return (0); 4697a8cf053SChristos Margiolis } 4707a8cf053SChristos Margiolis 4717a8cf053SChristos Margiolis int 4727a8cf053SChristos Margiolis dtrace_instr_c_sdsp(uint32_t **instr) 4737a8cf053SChristos Margiolis { 4747a8cf053SChristos Margiolis uint16_t *instr1; 4757a8cf053SChristos Margiolis int i; 4767a8cf053SChristos Margiolis 4777a8cf053SChristos Margiolis for (i = 0; i < 2; i++) { 4787a8cf053SChristos Margiolis instr1 = (uint16_t *)(*instr) + i; 4797a8cf053SChristos Margiolis if (dtrace_match_opcode(*instr1, (MATCH_C_SDSP | RS2_C_RA), 4807a8cf053SChristos Margiolis (MASK_C_SDSP | RS2_C_MASK))) { 4817a8cf053SChristos Margiolis *instr = (uint32_t *)instr1; 4827a8cf053SChristos Margiolis return (1); 4837a8cf053SChristos Margiolis } 4847a8cf053SChristos Margiolis } 4857a8cf053SChristos Margiolis 4867a8cf053SChristos Margiolis return (0); 4877a8cf053SChristos Margiolis } 4887a8cf053SChristos Margiolis 4897a8cf053SChristos Margiolis int 4907a8cf053SChristos Margiolis dtrace_instr_ret(uint32_t **instr) 4917a8cf053SChristos Margiolis { 4927a8cf053SChristos Margiolis if (dtrace_match_opcode(**instr, (MATCH_JALR | (X_RA << RS1_SHIFT)), 4937a8cf053SChristos Margiolis (MASK_JALR | RD_MASK | RS1_MASK | IMM_MASK))) 4947a8cf053SChristos Margiolis return (1); 4957a8cf053SChristos Margiolis 4967a8cf053SChristos Margiolis return (0); 4977a8cf053SChristos Margiolis } 4987a8cf053SChristos Margiolis 4997a8cf053SChristos Margiolis int 5007a8cf053SChristos Margiolis dtrace_instr_c_ret(uint32_t **instr) 5017a8cf053SChristos Margiolis { 5027a8cf053SChristos Margiolis uint16_t *instr1; 5037a8cf053SChristos Margiolis int i; 5047a8cf053SChristos Margiolis 5057a8cf053SChristos Margiolis for (i = 0; i < 2; i++) { 5067a8cf053SChristos Margiolis instr1 = (uint16_t *)(*instr) + i; 5077a8cf053SChristos Margiolis if (dtrace_match_opcode(*instr1, 5087a8cf053SChristos Margiolis (MATCH_C_JR | (X_RA << RD_SHIFT)), (MASK_C_JR | RD_MASK))) { 5097a8cf053SChristos Margiolis *instr = (uint32_t *)instr1; 5107a8cf053SChristos Margiolis return (1); 5117a8cf053SChristos Margiolis } 5127a8cf053SChristos Margiolis } 5137a8cf053SChristos Margiolis 5147a8cf053SChristos Margiolis return (0); 5157a8cf053SChristos Margiolis } 516