PERFORCE change 97782 for review
John Birrell
jb at FreeBSD.org
Thu May 25 01:42:07 UTC 2006
http://perforce.freebsd.org/chv.cgi?CH=97782
Change 97782 by jb at jb_freebsd2 on 2006/05/25 01:40:55
Add the asm code to handle FBT or SDT probes which are triggered by
execution of an invalid opcode (inserted as a replacement for a
valid one).
Affected files ...
.. //depot/projects/dtrace/src/sys/i386/i386/exception.s#2 edit
Differences ...
==== //depot/projects/dtrace/src/sys/i386/i386/exception.s#2 (text+ko) ====
@@ -30,16 +30,28 @@
* $FreeBSD: src/sys/i386/i386/exception.s,v 1.116 2006/04/04 02:26:45 jkoshy Exp $
*/
+/*
+ * The DTrace parts of this file are:
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
#include "opt_apic.h"
+#include "opt_kdtrace.h"
#include "opt_npx.h"
#include <machine/asmacros.h>
#include <machine/psl.h>
#include <machine/trap.h>
+#ifdef KDTRACE
+#include <machine/dtrace_asm.h>
+#endif
#include "assym.s"
#define SEL_RPL_MASK 0x0003
+#define GSEL_KPL 0x0020 /* GSEL(GCODE_SEL, SEL_KPL) */
.text
@@ -88,8 +100,6 @@
pushl $0; TRAP(T_OFLOW)
IDTVEC(bnd)
pushl $0; TRAP(T_BOUND)
-IDTVEC(ill)
- pushl $0; TRAP(T_PRIVINFLT)
IDTVEC(dna)
pushl $0; TRAP(T_DNA)
IDTVEC(fpusegm)
@@ -144,6 +154,163 @@
jmp doreti
/*
+ * Privileged instruction fault.
+ */
+ SUPERALIGN_TEXT
+IDTVEC(ill)
+#ifdef KDTRACE
+ /*
+ * DTrace uses invalid instructions to hook itself into
+ * the executable code. A privileged instruction fault in
+ * kernel code probably is the result of a 'Function Boundary
+ * Tracing' (FBT) or 'Statically Defined Tracing' (SDT)
+ * probe.
+ *
+ * Check if there is an invalid instruction function registered.
+ * (see trap.c for the global variable referenced)
+ */
+ cmpl $0, (dtrace_invop_func)
+
+ /* If not, just handle it as a normal trap. */
+ jz norm_ill
+
+ /* Check if this is a user fault. */
+ cmpl $GSEL_KPL, 4(%esp) /* Check the code segment. */
+
+ /* If so, just handle it as a normal trap. */
+ jne norm_ill
+
+ /*
+ * This is a kernel instruction fault that might have been caused
+ * by a DTrace provider.
+ */
+ pushal /* Push all registers onto the stack. */
+
+ /*
+ * Setup the stack to contain the arguments to:
+ * int dtrace_invop(uintptr_t addr, uintptr_t *stack, uintptr_t eax);
+ */
+ pushl %eax /* Push %eax -- may contain the return value. */
+ pushl %esp /* Push the stack pointer. */
+ addl $48, (%esp) /* Adjust to incoming args. */
+ pushl 40(%esp) /* Push the calling EIP. */
+
+ /* Call the registered function (dtrace_invop). */
+ call *dtrace_invop_func /* Call the registered function. */
+
+ /*
+ * Drop the arguments to dtrace_invop from the stack, leaving
+ * the registers.
+ */
+ addl $12, %esp
+
+ /* Process according to the return value from dtrace_invop. */
+ cmpl $DTRACE_INVOP_PUSHL_EBP, %eax
+ je 1f
+ cmpl $DTRACE_INVOP_POPL_EBP, %eax
+ je 2f
+ cmpl $DTRACE_INVOP_LEAVE, %eax
+ je 3f
+ cmpl $DTRACE_INVOP_NOP, %eax
+ je 4f
+
+ /*
+ * The registered DTrace invalid instruction functions didn't
+ * match the fault address to a probe, so process the trap in
+ * the normal way.
+ &/
+ * normal way because the registered DTrace invalid instruction
+ * functions didn't match it to a probe.
+ */
+ jmp norm_ill
+
+ /* case DTRACE_INVOP_PUSHL_EBP: */
+1:
+ /*
+ * We must emulate a "pushl %ebp". To do this, we pull the stack
+ * down 4 bytes, and then store the base pointer.
+ */
+ popal
+ subl $4, %esp /* make room for %ebp */
+ pushl %eax /* push temp */
+ movl 8(%esp), %eax /* load calling EIP */
+ incl %eax /* increment over LOCK prefix */
+ movl %eax, 4(%esp) /* store calling EIP */
+ movl 12(%esp), %eax /* load calling CS */
+ movl %eax, 8(%esp) /* store calling CS */
+ movl 16(%esp), %eax /* load calling EFLAGS */
+ movl %eax, 12(%esp) /* store calling EFLAGS */
+ movl %ebp, 16(%esp) /* push %ebp */
+ popl %eax /* pop off temp */
+ iret /* return from interrupt */
+
+ /* case DTRACE_INVOP_POPL_EBP: */
+2:
+ /*
+ * We must emulate a "popl %ebp". To do this, we do the opposite of
+ * the above: we remove the %ebp from the stack, and squeeze up the
+ * saved state from the trap.
+ */
+ popal
+ pushl %eax /* push temp */
+ movl 16(%esp), %ebp /* pop %ebp */
+ movl 12(%esp), %eax /* load calling EFLAGS */
+ movl %eax, 16(%esp) /* store calling EFLAGS */
+ movl 8(%esp), %eax /* load calling CS */
+ movl %eax, 12(%esp) /* store calling CS */
+ movl 4(%esp), %eax /* load calling EIP */
+ incl %eax /* increment over LOCK prefix */
+ movl %eax, 8(%esp) /* store calling EIP */
+ popl %eax /* pop off temp */
+ addl $4, %esp /* adjust stack pointer */
+ iret /* return from interrupt */
+
+ /* case DTRACE_INVOP_LEAVE: */
+3:
+ /*
+ * We must emulate a "leave", which is the same as a "movl %ebp, %esp"
+ * followed by a "popl %ebp". This looks similar to the above, but
+ * requires two temporaries: one for the new base pointer, and one
+ * for the staging register.
+ */
+ popal
+ pushl %eax /* push temp */
+ pushl %ebx /* push temp */
+ movl %ebp, %ebx /* set temp to old %ebp */
+ movl (%ebx), %ebp /* pop %ebp */
+ movl 16(%esp), %eax /* load calling EFLAGS */
+ movl %eax, (%ebx) /* store calling EFLAGS */
+ movl 12(%esp), %eax /* load calling CS */
+ movl %eax, -4(%ebx) /* store calling CS */
+ movl 8(%esp), %eax /* load calling EIP */
+ incl %eax /* increment over LOCK prefix */
+ movl %eax, -8(%ebx) /* store calling EIP */
+ movl %ebx, -4(%esp) /* temporarily store new %esp */
+ popl %ebx /* pop off temp */
+ popl %eax /* pop off temp */
+ movl -12(%esp), %esp /* set stack pointer */
+ subl $8, %esp /* adjust for three pushes, one pop */
+ iret /* return from interrupt */
+
+ /* case DTRACE_INVOP_NOP: */
+4:
+ /*
+ * We must emulate a "nop". This is obviously not hard: we need only
+ * advance the %eip by one.
+ */
+ popal
+ incl (%esp)
+ iret
+
+norm_ill:
+#endif
+ /*
+ * Process the instruction fault in the normal way.
+ */
+ pushl $0
+ TRAP(T_PRIVINFLT)
+
+/*
* SYSCALL CALL GATE (old entry point for a.out binaries)
*
* The intersegment call has been set up to specify one dummy parameter.
More information about the p4-projects
mailing list