]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/dev/i386/sdt_x86.c
xnu-6153.61.1.tar.gz
[apple/xnu.git] / bsd / dev / i386 / sdt_x86.c
index eb1c2ecffe0b30ad4efc1a2c859191932f5ecb94..4b78fe79101ce618e7a0aea6ec28757159f05d69 100644 (file)
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
-/* #pragma ident       "@(#)sdt.c      1.6     06/03/24 SMI" */
-
-#ifdef KERNEL
-#ifndef _KERNEL
-#define _KERNEL /* Solaris vs. Darwin */
-#endif
-#endif
-
-#define MACH__POSIX_C_SOURCE_PRIVATE 1 /* pulls in suitable savearea from mach/ppc/thread_status.h */
 #include <kern/cpu_data.h>
 #include <kern/thread.h>
 #include <mach/thread_status.h>
@@ -51,34 +42,111 @@ int
 sdt_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax)
 {
 #pragma unused(eax)
-       uintptr_t stack0 = 0, stack1 = 0, stack2 = 0, stack3 = 0, stack4 = 0;
        sdt_probe_t *sdt = sdt_probetab[SDT_ADDR2NDX(addr)];
 
        for (; sdt != NULL; sdt = sdt->sdp_hashnext) {
                if ((uintptr_t)sdt->sdp_patchpoint == addr) {
-                        uintptr_t *stacktop;
-                        if (CPU_ON_INTR(CPU))
-                                stacktop = (uintptr_t *)dtrace_get_cpu_int_stack_top();
-                        else
-                                stacktop = (uintptr_t *)(dtrace_get_kernel_stack(current_thread()) + KERNEL_STACK_SIZE);
-
-            if (stack <= stacktop)
-                stack0 = *stack++;
-            if (stack <= stacktop)
-                stack1 = *stack++;
-            if (stack <= stacktop)
-                stack2 = *stack++;
-            if (stack <= stacktop)
-                stack3 = *stack++;
-            if (stack <= stacktop)
-                stack4 = *stack++;
-
-                       dtrace_probe(sdt->sdp_id, stack0, stack1, stack2, stack3, stack4);
-
-                       return (DTRACE_INVOP_NOP);
+                       x86_saved_state64_t *regs = (x86_saved_state64_t *)stack;
+
+                       dtrace_probe(sdt->sdp_id, regs->rdi, regs->rsi, regs->rdx, regs->rcx, regs->r8);
+
+                       return DTRACE_INVOP_NOP;
                }
        }
 
-       return (0);
+       return 0;
 }
 
+
+struct frame {
+       struct frame *backchain;
+       uintptr_t retaddr;
+};
+
+/*ARGSUSED*/
+uint64_t
+sdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, int aframes)
+{
+#pragma unused(arg, id, parg)
+       uint64_t val;
+       struct frame *fp = (struct frame *)__builtin_frame_address(0);
+       uintptr_t *stack;
+       uintptr_t pc;
+       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->backchain;
+               pc = fp->retaddr;
+
+               if (dtrace_invop_callsite_pre != NULL
+                   && pc > (uintptr_t)dtrace_invop_callsite_pre
+                   && pc <= (uintptr_t)dtrace_invop_callsite_post) {
+                       /*
+                        * In the case of x86_64, we will use the pointer to the
+                        * save area 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.
+                        */
+
+                       /* fp points to frame of dtrace_invop() activation. */
+                       fp = fp->backchain; /* to fbt_perfcallback() activation. */
+                       fp = fp->backchain; /* to kernel_trap() activation. */
+                       fp = fp->backchain; /* to trap_from_kernel() activation. */
+
+                       x86_saved_state_t   *tagged_regs = (x86_saved_state_t *)&fp[1];
+                       x86_saved_state64_t *saved_state = saved_state64(tagged_regs);
+
+                       if (argno <= inreg) {
+                               stack = (uintptr_t *)(void*)&saved_state->rdi;
+                       } else {
+                               fp = (struct frame *)(saved_state->isf.rsp);
+                               stack = (uintptr_t *)&fp[0]; /* Find marshalled
+                                                             *  arguments */
+                               argno -= (inreg + 1);
+                       }
+                       goto load;
+               }
+       }
+
+       /*
+        * We know that we did not come through a trap to get into
+        * dtrace_probe() --  We arrive here when the provider has
+        * called dtrace_probe() directly.
+        * The probe ID is the first argument to dtrace_probe().
+        * We must advance beyond that to get the argX.
+        */
+       argno++; /* Advance past probeID */
+
+       if (argno <= 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;
+       }
+
+       argno -= (inreg + 1);
+       stack = (uintptr_t *)&fp[1]; /* Find marshalled arguments */
+
+load:
+       DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
+       /* dtrace_probe arguments arg0 ... arg4 are 64bits wide */
+       val = (uint64_t)(*(((uintptr_t *)stack) + argno));
+       DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT);
+
+       return val;
+}