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/*ARGSUSED*/ 50int 51sdt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax) 52{ 53#pragma unused(eax) 54 sdt_probe_t *sdt = sdt_probetab[SDT_ADDR2NDX(addr)]; 55 56 for (; sdt != NULL; sdt = sdt->sdp_hashnext) { 57 if ((uintptr_t)sdt->sdp_patchpoint == addr) { 58 x86_saved_state64_t *regs = (x86_saved_state64_t *)stack; 59 60 dtrace_probe(sdt->sdp_id, regs->rdi, regs->rsi, regs->rdx, regs->rcx, regs->r8); 61 62 return (DTRACE_INVOP_NOP); 63 } 64 } 65 66 return (0); 67} 68 69 70struct frame { 71 struct frame *backchain; 72 uintptr_t retaddr; 73}; 74 75/*ARGSUSED*/ 76uint64_t 77sdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, int aframes) 78{ 79#pragma unused(arg, id, parg) 80 uint64_t val; 81 struct frame *fp = (struct frame *)__builtin_frame_address(0); 82 uintptr_t *stack; 83 uintptr_t pc; 84 int i; 85 86 /* 87 * A total of 6 arguments are passed via registers; any argument with 88 * index of 5 or lower is therefore in a register. 89 */ 90 int inreg = 5; 91 92 for (i = 1; i <= aframes; i++) { 93 fp = fp->backchain; 94 pc = fp->retaddr; 95 96 if (dtrace_invop_callsite_pre != NULL 97 && pc > (uintptr_t)dtrace_invop_callsite_pre 98 && pc <= (uintptr_t)dtrace_invop_callsite_post) { 99 /* 100 * In the case of x86_64, we will use the pointer to the 101 * save area structure that was pushed when we took the 102 * trap. To get this structure, we must increment 103 * beyond the frame structure. If the 104 * argument that we're seeking is passed on the stack, 105 * we'll pull the true stack pointer out of the saved 106 * registers and decrement our argument by the number 107 * of arguments passed in registers; if the argument 108 * we're seeking is passed in regsiters, we can just 109 * load it directly. 110 */ 111 112 /* fp points to frame of dtrace_invop() activation. */ 113 fp = fp->backchain; /* to fbt_perfcallback() activation. */ 114 fp = fp->backchain; /* to kernel_trap() activation. */ 115 fp = fp->backchain; /* to trap_from_kernel() activation. */ 116 117 x86_saved_state_t *tagged_regs = (x86_saved_state_t *)&fp[1]; 118 x86_saved_state64_t *saved_state = saved_state64(tagged_regs); 119 120 if (argno <= inreg) { 121 stack = (uintptr_t *)&saved_state->rdi; 122 } else { 123 fp = (struct frame *)(saved_state->isf.rsp); 124 stack = (uintptr_t *)&fp[0]; /* Find marshalled 125 arguments */ 126 argno -= (inreg +1); 127 } 128 goto load; 129 } 130 } 131 132 /* 133 * We know that we did not come through a trap to get into 134 * dtrace_probe() -- We arrive here when the provider has 135 * called dtrace_probe() directly. 136 * The probe ID is the first argument to dtrace_probe(). 137 * We must advance beyond that to get the argX. 138 */ 139 argno++; /* Advance past probeID */ 140 141 if (argno <= inreg) { 142 /* 143 * This shouldn't happen. If the argument is passed in a 144 * register then it should have been, well, passed in a 145 * register... 146 */ 147 DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP); 148 return (0); 149 } 150 151 argno -= (inreg + 1); 152 stack = (uintptr_t *)&fp[1]; /* Find marshalled arguments */ 153 154load: 155 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT); 156 /* dtrace_probe arguments arg0 ... arg4 are 64bits wide */ 157 val = (uint64_t)(*(((uintptr_t *)stack) + argno)); 158 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT); 159 160 return (val); 161} 162 163