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