1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21/* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26/* #pragma ident "@(#)sdt.c 1.9 08/07/01 SMI" */ 27 28#ifdef KERNEL 29#ifndef _KERNEL 30#define _KERNEL /* Solaris vs. Darwin */ 31#endif 32#endif 33 34#define MACH__POSIX_C_SOURCE_PRIVATE 1 /* pulls in suitable savearea from mach/ppc/thread_status.h */ 35#include <kern/cpu_data.h> 36#include <kern/thread.h> 37#include <mach/thread_status.h> 38#include <mach/vm_param.h> 39 40#include <sys/dtrace.h> 41#include <sys/dtrace_impl.h> 42 43#include <sys/dtrace_glue.h> 44 45#include <sys/sdt_impl.h> 46 47extern sdt_probe_t **sdt_probetab; 48 49#if defined(__i386__) 50/*ARGSUSED*/ 51int 52sdt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax) 53{ 54#pragma unused(eax) 55 uintptr_t stack0 = 0, stack1 = 0, stack2 = 0, stack3 = 0, stack4 = 0; 56 sdt_probe_t *sdt = sdt_probetab[SDT_ADDR2NDX(addr)]; 57 58 for (; sdt != NULL; sdt = sdt->sdp_hashnext) { 59 if ((uintptr_t)sdt->sdp_patchpoint == addr) { 60 uintptr_t *stacktop; 61 if (CPU_ON_INTR(CPU)) 62 stacktop = (uintptr_t *)dtrace_get_cpu_int_stack_top(); 63 else 64 stacktop = (uintptr_t *)(dtrace_get_kernel_stack(current_thread()) + kernel_stack_size); 65 66 if (stack <= stacktop) 67 stack0 = *stack++; 68 if (stack <= stacktop) 69 stack1 = *stack++; 70 if (stack <= stacktop) 71 stack2 = *stack++; 72 if (stack <= stacktop) 73 stack3 = *stack++; 74 if (stack <= stacktop) 75 stack4 = *stack++; 76 77 dtrace_probe(sdt->sdp_id, stack0, stack1, stack2, stack3, stack4); 78 79 return (DTRACE_INVOP_NOP); 80 } 81 } 82 83 return (0); 84} 85#elif defined(__x86_64__) 86/*ARGSUSED*/ 87int 88sdt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax) 89{ 90#pragma unused(eax) 91 sdt_probe_t *sdt = sdt_probetab[SDT_ADDR2NDX(addr)]; 92 93 for (; sdt != NULL; sdt = sdt->sdp_hashnext) { 94 if ((uintptr_t)sdt->sdp_patchpoint == addr) { 95 x86_saved_state64_t *regs = (x86_saved_state64_t *)stack; 96 97 dtrace_probe(sdt->sdp_id, regs->rdi, regs->rsi, regs->rdx, regs->rcx, regs->r8); 98 99 return (DTRACE_INVOP_NOP); 100 } 101 } 102 103 return (0); 104} 105#else 106#error Unknown arch 107#endif 108 109 110struct frame { 111 struct frame *backchain; 112 uintptr_t retaddr; 113}; 114 115/*ARGSUSED*/ 116uint64_t 117sdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, int aframes) 118{ 119#pragma unused(arg, id, parg) 120 uint64_t val; 121 struct frame *fp = (struct frame *)__builtin_frame_address(0); 122 uintptr_t *stack; 123 uintptr_t pc; 124 int i; 125 126#if defined(__x86_64__) 127 /* 128 * A total of 6 arguments are passed via registers; any argument with 129 * index of 5 or lower is therefore in a register. 130 */ 131 int inreg = 5; 132#endif 133 134 for (i = 1; i <= aframes; i++) { 135 fp = fp->backchain; 136 pc = fp->retaddr; 137 138 if (dtrace_invop_callsite_pre != NULL 139 && pc > (uintptr_t)dtrace_invop_callsite_pre 140 && pc <= (uintptr_t)dtrace_invop_callsite_post) { 141#if defined(__i386__) 142 /* 143 * If we pass through the invalid op handler, we will 144 * use the pointer that it passed to the stack as the 145 * second argument to dtrace_invop() as the pointer to 146 * the frame we're hunting for. 147 */ 148 149 stack = (uintptr_t *)&fp[1]; /* Find marshalled arguments */ 150 fp = (struct frame *)stack[1]; /* Grab *second* argument */ 151 stack = (uintptr_t *)&fp[0]; /* Find marshalled arguments */ 152#elif defined(__x86_64__) 153 /* 154 * In the case of x86_64, we will use the pointer to the 155 * save area structure that was pushed when we took the 156 * trap. To get this structure, we must increment 157 * beyond the frame structure. If the 158 * argument that we're seeking is passed on the stack, 159 * we'll pull the true stack pointer out of the saved 160 * registers and decrement our argument by the number 161 * of arguments passed in registers; if the argument 162 * we're seeking is passed in regsiters, we can just 163 * load it directly. 164 */ 165 166 /* fp points to frame of dtrace_invop() activation. */ 167 fp = fp->backchain; /* to fbt_perfcallback() activation. */ 168 fp = fp->backchain; /* to kernel_trap() activation. */ 169 fp = fp->backchain; /* to trap_from_kernel() activation. */ 170 171 x86_saved_state_t *tagged_regs = (x86_saved_state_t *)&fp[1]; 172 x86_saved_state64_t *saved_state = saved_state64(tagged_regs); 173 174 if (argno <= inreg) { 175 stack = (uintptr_t *)&saved_state->rdi; 176 } else { 177 fp = (struct frame *)(saved_state->isf.rsp); 178 stack = (uintptr_t *)&fp[0]; /* Find marshalled 179 arguments */ 180 argno -= (inreg +1); 181 } 182#else 183#error Unknown arch 184#endif 185 goto load; 186 } 187 } 188 189 /* 190 * We know that we did not come through a trap to get into 191 * dtrace_probe() -- We arrive here when the provider has 192 * called dtrace_probe() directly. 193 * The probe ID is the first argument to dtrace_probe(). 194 * We must advance beyond that to get the argX. 195 */ 196 argno++; /* Advance past probeID */ 197 198#if defined(__x86_64__) 199 if (argno <= inreg) { 200 /* 201 * This shouldn't happen. If the argument is passed in a 202 * register then it should have been, well, passed in a 203 * register... 204 */ 205 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 206 return (0); 207 } 208 209 argno -= (inreg + 1); 210#endif 211 stack = (uintptr_t *)&fp[1]; /* Find marshalled arguments */ 212 213load: 214 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); 215 /* dtrace_probe arguments arg0 ... arg4 are 64bits wide */ 216 val = (uint64_t)(*(((uintptr_t *)stack) + argno)); 217 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); 218 219 return (val); 220} 221 222