changeset 13864:2737b2ab1b9e

3169 userland amd64 code should save arguments 3180 mdb should handle push-based argument save area 3192 mdb save-args matching should accept more agressive insn scheduling 3193 mdb save-args matching should only consider insns which have executed Reviewed by: Robert Mustacchi <rm@joyent.com> Reviewed by: Garrett D'Amore <garrett@damore.org> Reviewed by: Eric Schrock <eric.schrock@delphix.com> Reviewed by: Hans Rosenfeld <hans.rosenfeld@nexenta.com> Approved by: Garrett D'Amore <garrett@damore.org>
author Richard Lowe <richlowe@richlowe.net>
date Fri, 07 Sep 2012 23:51:24 -0400
parents 3972d90e0f77
children 6fa12cf47ebb
files usr/src/Makefile.master usr/src/Makefile.master.64 usr/src/cmd/mdb/intel/amd64/Makefile.kmdb usr/src/cmd/mdb/intel/amd64/mdb/Makefile usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c usr/src/common/saveargs/saveargs.c usr/src/common/saveargs/saveargs.h usr/src/common/saveargs/tests/README usr/src/common/saveargs/tests/functional/Makefile usr/src/common/saveargs/tests/functional/align.c usr/src/common/saveargs/tests/functional/basic.c usr/src/common/saveargs/tests/functional/big-struct-ret-and-spill.c usr/src/common/saveargs/tests/functional/big-struct-ret.c usr/src/common/saveargs/tests/functional/small-struct-ret-and-spill.c usr/src/common/saveargs/tests/functional/small-struct-ret.c usr/src/common/saveargs/tests/functional/stack-spill.c usr/src/common/saveargs/tests/functional/test.sh usr/src/common/saveargs/tests/testmatch/Makefile usr/src/common/saveargs/tests/testmatch/data.s usr/src/common/saveargs/tests/testmatch/testmatch.c usr/src/lib/libproc/Makefile.com usr/src/lib/libproc/amd64/Pisadep.c usr/src/tools/findunref/exception_list.open usr/src/uts/Makefile.uts usr/src/uts/sparc/Makefile.sparc.shared usr/src/uts/sun4u/Makefile.sun4u.shared usr/src/uts/sun4v/Makefile.sun4v.shared
diffstat 27 files changed, 1472 insertions(+), 200 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/Makefile.master	Thu Oct 18 16:38:42 2012 +0000
+++ b/usr/src/Makefile.master	Fri Sep 07 23:51:24 2012 -0400
@@ -479,7 +479,16 @@
 #
 CTF_FLAGS_sparc	= -g -Wc,-Qiselect-T1 $(C99MODE) $(CNOGLOBAL) $(CDWARFSTR)
 CTF_FLAGS_i386	= -g $(C99MODE) $(CNOGLOBAL) $(CDWARFSTR)
-CTF_FLAGS	= $(CTF_FLAGS_$(MACH)) $(DEBUGFORMAT)
+
+CTF_FLAGS_sparcv9	= $(CTF_FLAGS_sparc)
+CTF_FLAGS_amd64		= $(CTF_FLAGS_i386)
+
+# Sun Studio produces broken userland code when saving arguments.
+$(__GNUC)CTF_FLAGS_amd64 += $(SAVEARGS)
+
+CTF_FLAGS_32	= $(CTF_FLAGS_$(MACH)) $(DEBUGFORMAT)
+CTF_FLAGS_64	= $(CTF_FLAGS_$(MACH64)) $(DEBUGFORMAT)
+CTF_FLAGS	= $(CTF_FLAGS_32)
 
 #
 # Flags used with genoffsets
--- a/usr/src/Makefile.master.64	Thu Oct 18 16:38:42 2012 +0000
+++ b/usr/src/Makefile.master.64	Fri Sep 07 23:51:24 2012 -0400
@@ -37,6 +37,8 @@
 LINK.cc=	$(LINK64.cc)
 LINT.c=		$(LINT64.c)
 
+CTF_FLAGS=	$(CTF_FLAGS_64)
+
 OFFSETS_CREATE=	$(OFFSETS_CREATE64)
 
 #
--- a/usr/src/cmd/mdb/intel/amd64/Makefile.kmdb	Thu Oct 18 16:38:42 2012 +0000
+++ b/usr/src/cmd/mdb/intel/amd64/Makefile.kmdb	Fri Sep 07 23:51:24 2012 -0400
@@ -22,8 +22,6 @@
 # Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
-#
 
 KMDBML += \
 	kaif_invoke.s \
@@ -31,6 +29,15 @@
 
 KMDBSRCS += \
 	kmdb_makecontext.c \
-	mdb_amd64util.c
+	mdb_amd64util.c \
+	saveargs.c
+
+%.o: $(SRC)/common/saveargs/%.c
+	$(COMPILE.c) $<
+	$(CTFCONVERT_O)
+
+%.ln: $(SRC)/common/saveargs/%.c
+	$(LINT.c) -c $<
 
 SACPPFLAGS = -D__$(MACH64) -U__$(MACH)
+CPPFLAGS += -I$(SRC)/common/saveargs
--- a/usr/src/cmd/mdb/intel/amd64/mdb/Makefile	Thu Oct 18 16:38:42 2012 +0000
+++ b/usr/src/cmd/mdb/intel/amd64/mdb/Makefile	Fri Sep 07 23:51:24 2012 -0400
@@ -22,12 +22,12 @@
 # Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
-#ident	"%Z%%M%	%I%	%E% SMI"
 
 SRCS =	kvm_amd64dep.c \
 	kvm_isadep.c \
 	mdb_amd64util.c \
-	proc_amd64dep.c
+	proc_amd64dep.c \
+	saveargs.c
 
 %.o: %.c
 	$(COMPILE.c) $<
@@ -37,17 +37,25 @@
 	$(COMPILE.c) $<
 	$(CTFCONVERT_O)
 
+%.o: $(SRC)/common/saveargs/%.c
+	$(COMPILE.c) $<
+	$(CTFCONVERT_O)
+
 %.ln: %.c
 	$(LINT.c) -c $<
 
 %.ln: ../../mdb/%.c
 	$(LINT.c) -c $<
 
+%.ln: $(SRC)/common/saveargs/%.c
+	$(LINT.c) -c $<
+
 include ../../../../Makefile.cmd
 include ../../../../Makefile.cmd.64
 include ../../Makefile.amd64
 include ../../../Makefile.mdb
 
 CPPFLAGS += -I../../mdb
+CPPFLAGS += -I$(SRC)/common/saveargs
 
 install: all $(ISAEXEC) $(ROOTPROG64) $(ROOTLINK64)
--- a/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c	Thu Oct 18 16:38:42 2012 +0000
+++ b/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c	Fri Sep 07 23:51:24 2012 -0400
@@ -24,8 +24,6 @@
  * Use is subject to license terms.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/reg.h>
 #include <sys/privregs.h>
@@ -41,6 +39,8 @@
 #include <mdb/mdb_err.h>
 #include <mdb/mdb.h>
 
+#include <saveargs.h>
+
 /*
  * This array is used by the getareg and putareg entry points, and also by our
  * register variable discipline.
@@ -138,170 +138,6 @@
 }
 
 /*
- * Sun Studio 10 patch compiler and gcc 3.4.3 Sun branch implemented a
- * "-save_args" option on amd64.  When the option is specified, INTEGER
- * type function arguments passed via registers will be saved on the stack
- * immediately after %rbp, and will not be modified through out the life
- * of the routine.
- *
- *				+--------+
- *		%rbp	-->     |  %rbp  |
- *				+--------+
- *		-0x8(%rbp)	|  %rdi  |
- *				+--------+
- *		-0x10(%rbp)	|  %rsi  |
- *				+--------+
- *		-0x18(%rbp)	|  %rdx  |
- *				+--------+
- *		-0x20(%rbp)	|  %rcx  |
- *				+--------+
- *		-0x28(%rbp)	|  %r8   |
- *				+--------+
- *		-0x30(%rbp)	|  %r9   |
- *				+--------+
- *
- *
- * For example, for the following function,
- *
- * void
- * foo(int a1, int a2, int a3, int a4, int a5, int a6, int a7)
- * {
- * ...
- * }
- *
- * Disassembled code will look something like the following:
- *
- *     pushq	%rbp
- *     movq	%rsp, %rbp
- *     subq	$imm8, %rsp			**
- *     movq	%rdi, -0x8(%rbp)
- *     movq	%rsi, -0x10(%rbp)
- *     movq	%rdx, -0x18(%rbp)
- *     movq	%rcx, -0x20(%rbp)
- *     movq	%r8, -0x28(%rbp)
- *     movq	%r9, -0x30(%rbp)
- *     ...
- * or
- *     pushq	%rbp
- *     movq	%rsp, %rbp
- *     subq	$imm8, %rsp			**
- *     movq	%r9, -0x30(%rbp)
- *     movq	%r8, -0x28(%rbp)
- *     movq	%rcx, -0x20(%rbp)
- *     movq	%rdx, -0x18(%rbp)
- *     movq	%rsi, -0x10(%rbp)
- *     movq	%rdi, -0x8(%rbp)
- *     ...
- *
- * **: The space being reserved is in addition to what the current
- *     function prolog already reserves.
- *
- * If there are odd number of arguments to a function, additional space is
- * reserved on the stack to maintain 16-byte alignment.  For example,
- *
- *     argc == 0: no argument saving.
- *     argc == 3: save 3, but space for 4 is reserved
- *     argc == 7: save 6.
- */
-
-/*
- * The longest instruction sequence in bytes before all 6 arguments are
- * saved on the stack.  This value depends on compiler implementation,
- * therefore it should be examined periodically to guarantee accuracy.
- */
-#define	SEQ_LEN		80
-
-/*
- * Size of the instruction sequence arrays.  It should correspond to
- * the maximum number of arguments passed via registers.
- */
-#define	INSTR_ARRAY_SIZE	6
-
-#define	INSTR4(ins, off)	\
-	(ins[(off)] + (ins[(off) + 1] << 8) + (ins[(off + 2)] << 16) + \
-	(ins[(off) + 3] << 24))
-
-/*
- * Sun Studio 10 patch implementation saves %rdi first;
- * GCC 3.4.3 Sun branch implementation saves them in reverse order.
- */
-static const uint32_t save_instr[INSTR_ARRAY_SIZE] = {
-	0xf87d8948,	/* movq %rdi, -0x8(%rbp) */
-	0xf0758948,	/* movq %rsi, -0x10(%rbp) */
-	0xe8558948,	/* movq %rdx, -0x18(%rbp) */
-	0xe04d8948,	/* movq %rcx, -0x20(%rbp) */
-	0xd845894c,	/* movq %r8, -0x28(%rbp) */
-	0xd04d894c	/* movq %r9, -0x30(%rbp) */
-};
-
-static const uint32_t save_fp_instr[] = {
-	0xe5894855,	/* pushq %rbp; movq %rsp,%rbp, encoding 1 */
-	0xec8b4855,	/* pushq %rbp; movq %rsp,%rbp, encoding 2 */
-	0xe58948cc,	/* int $0x3; movq %rsp,%rbp, encoding 1 */
-	0xec8b48cc,	/* int $0x3; movq %rsp,%rbp, encoding 2 */
-	NULL
-};
-
-/*
- * Look for the above instruction sequences as indicators for register
- * arguments being available on the stack.
- */
-static int
-is_argsaved(mdb_tgt_t *t, uintptr_t fstart, uint64_t size, uint_t argc,
-    int start_index)
-{
-	uint8_t		ins[SEQ_LEN];
-	int		i, j;
-	uint32_t	n;
-
-	size = MIN(size, SEQ_LEN);
-	argc = MIN((start_index + argc), INSTR_ARRAY_SIZE);
-
-	if (mdb_tgt_vread(t, ins, size, fstart) != size)
-		return (0);
-
-	/*
-	 * Make sure framepointer has been saved.
-	 */
-	n = INSTR4(ins, 0);
-	for (i = 0; save_fp_instr[i] != NULL; i++) {
-		if (n == save_fp_instr[i])
-			break;
-	}
-
-	if (save_fp_instr[i] == NULL)
-		return (0);
-
-	/*
-	 * Compare against Sun Studio implementation
-	 */
-	for (i = 8, j = start_index; i < size - 4; i++) {
-		n = INSTR4(ins, i);
-
-		if (n == save_instr[j]) {
-			i += 3;
-			if (++j >= argc)
-				return (1);
-		}
-	}
-
-	/*
-	 * Compare against GCC implementation
-	 */
-	for (i = 8, j = argc - 1; i < size - 4; i++) {
-		n = INSTR4(ins, i);
-
-		if (n == save_instr[j]) {
-			i += 3;
-			if (--j < start_index)
-				return (1);
-		}
-	}
-
-	return (0);
-}
-
-/*
  * We expect all proper Solaris core files to have STACK_ALIGN-aligned stacks.
  * Hence the name.  However, if the core file resulted from a
  * hypervisor-initiated panic, the hypervisor's frames may only be 64-bit
@@ -339,6 +175,8 @@
 	uintptr_t lastfp, curpc;
 
 	ssize_t size;
+	ssize_t insnsize;
+	uint8_t ins[SAVEARGS_INSN_SEQ_LEN];
 
 	GElf_Sym s;
 	mdb_syminfo_t sip;
@@ -354,6 +192,7 @@
 	bcopy(gsp, &gregs, sizeof (gregs));
 
 	while (fp != 0) {
+		int args_style = 0;
 
 		curpc = pc;
 
@@ -367,28 +206,75 @@
 		    NULL, 0, &s, &sip) == 0) &&
 		    (mdb_ctf_func_info(&s, &sip, &mfp) == 0)) {
 			int return_type = mdb_ctf_type_kind(mfp.mtf_return);
+			mdb_ctf_id_t args_types[5];
+
 			argc = mfp.mtf_argc;
+
 			/*
-			 * If the function returns a structure or union,
-			 * %rdi contains the address in which to store the
-			 * return value rather than for an argument.
+			 * If the function returns a structure or union
+			 * greater than 16 bytes in size %rdi contains the
+			 * address in which to store the return value rather
+			 * than for an argument.
 			 */
-			if (return_type == CTF_K_STRUCT ||
-			    return_type == CTF_K_UNION)
+			if ((return_type == CTF_K_STRUCT ||
+			    return_type == CTF_K_UNION) &&
+			    mdb_ctf_type_size(mfp.mtf_return) > 16)
 				start_index = 1;
 			else
 				start_index = 0;
+
+			/*
+			 * If any of the first 5 arguments are a structure
+			 * less than 16 bytes in size, it will be passed
+			 * spread across two argument registers, and we will
+			 * not cope.
+			 */
+			if (mdb_ctf_func_args(&mfp, 5, args_types) == CTF_ERR)
+				argc = 0;
+
+			for (i = 0; i < MIN(5, argc); i++) {
+				int t = mdb_ctf_type_kind(args_types[i]);
+
+				if (((t == CTF_K_STRUCT) ||
+				    (t == CTF_K_UNION)) &&
+				    mdb_ctf_type_size(args_types[i]) <= 16) {
+					argc = 0;
+					break;
+				}
+			}
 		} else {
 			argc = 0;
 		}
 
-		if (argc != 0 && is_argsaved(t, s.st_value, s.st_size,
-		    argc, start_index)) {
+		/*
+		 * The number of instructions to search for argument saving is
+		 * limited such that only instructions prior to %pc are
+		 * considered such that we never read arguments from a
+		 * function where the saving code has not in fact yet
+		 * executed.
+		 */
+		insnsize = MIN(MIN(s.st_size, SAVEARGS_INSN_SEQ_LEN),
+		    pc - s.st_value);
+
+		if (mdb_tgt_vread(t, ins, insnsize, s.st_value) != insnsize)
+			argc = 0;
 
-			/* Upto to 6 arguments are passed via registers */
-			reg_argc = MIN(6, mfp.mtf_argc);
+		if ((argc != 0) &&
+		    ((args_style = saveargs_has_args(ins, insnsize, argc,
+		    start_index)) != SAVEARGS_NO_ARGS)) {
+			/* Up to 6 arguments are passed via registers */
+			reg_argc = MIN((6 - start_index), mfp.mtf_argc);
 			size = reg_argc * sizeof (long);
 
+			/*
+			 * If Studio pushed a structure return address as an
+			 * argument, we need to read one more argument than
+			 * actually exists (the addr) to make everything line
+			 * up.
+			 */
+			if (args_style == SAVEARGS_STRUCT_ARGS)
+				size += sizeof (long);
+
 			if (mdb_tgt_vread(t, fr_argv, size, (fp - size))
 			    != size)
 				return (-1);	/* errno has been set for us */
@@ -397,21 +283,25 @@
 			 * Arrange the arguments in the right order for
 			 * printing.
 			 */
-			for (i = 0; i < (reg_argc >> 1); i++) {
+			for (i = 0; i < (reg_argc / 2); i++) {
 				long t = fr_argv[i];
 
 				fr_argv[i] = fr_argv[reg_argc - i - 1];
 				fr_argv[reg_argc - i - 1] = t;
 			}
 
-			if (argc > 6) {
-				size = (argc - 6) * sizeof (long);
-				if (mdb_tgt_vread(t, &fr_argv[6], size,
+			if (argc > reg_argc) {
+				size = MIN((argc - reg_argc) * sizeof (long),
+				    sizeof (fr_argv) -
+				    (reg_argc * sizeof (long)));
+
+				if (mdb_tgt_vread(t, &fr_argv[reg_argc], size,
 				    fp + sizeof (fr)) != size)
 					return (-1); /* errno has been set */
 			}
-		} else
+		} else {
 			argc = 0;
+		}
 
 		if (got_pc && func(arg, pc, argc, fr_argv, &gregs) != 0)
 			break;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/saveargs/saveargs.c	Fri Sep 07 23:51:24 2012 -0400
@@ -0,0 +1,268 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+/*
+ * The Sun Studio and GCC (patched for opensolaris/illumos) compilers
+ * implement a argument saving scheme on amd64 via the -Wu,save-args or
+ * options.  When the option is specified, INTEGER type function arguments
+ * passed via registers will be saved on the stack immediately after %rbp, and
+ * will not be modified through out the life of the routine.
+ *
+ *				+--------+
+ *		%rbp	-->     |  %rbp  |
+ *				+--------+
+ *		-0x8(%rbp)	|  %rdi  |
+ *				+--------+
+ *		-0x10(%rbp)	|  %rsi  |
+ *				+--------+
+ *		-0x18(%rbp)	|  %rdx  |
+ *				+--------+
+ *		-0x20(%rbp)	|  %rcx  |
+ *				+--------+
+ *		-0x28(%rbp)	|  %r8   |
+ *				+--------+
+ *		-0x30(%rbp)	|  %r9   |
+ *				+--------+
+ *
+ *
+ * For example, for the following function,
+ *
+ * void
+ * foo(int a1, int a2, int a3, int a4, int a5, int a6, int a7)
+ * {
+ * ...
+ * }
+ *
+ * Disassembled code will look something like the following:
+ *
+ *     pushq	%rbp
+ *     movq	%rsp, %rbp
+ *     subq	$imm8, %rsp			**
+ *     movq	%rdi, -0x8(%rbp)
+ *     movq	%rsi, -0x10(%rbp)
+ *     movq	%rdx, -0x18(%rbp)
+ *     movq	%rcx, -0x20(%rbp)
+ *     movq	%r8, -0x28(%rbp)
+ *     movq	%r9, -0x30(%rbp)
+ *     ...
+ * or
+ *     pushq	%rbp
+ *     movq	%rsp, %rbp
+ *     subq	$imm8, %rsp			**
+ *     movq	%r9, -0x30(%rbp)
+ *     movq	%r8, -0x28(%rbp)
+ *     movq	%rcx, -0x20(%rbp)
+ *     movq	%rdx, -0x18(%rbp)
+ *     movq	%rsi, -0x10(%rbp)
+ *     movq	%rdi, -0x8(%rbp)
+ *     ...
+ * or
+ *     pushq	%rbp
+ *     movq	%rsp, %rbp
+ *     pushq	%rdi
+ *     pushq	%rsi
+ *     pushq	%rdx
+ *     pushq	%rcx
+ *     pushq	%r8
+ *     pushq	%r9
+ *
+ * **: The space being reserved is in addition to what the current
+ *     function prolog already reserves.
+ *
+ * We loop through the first SAVEARGS_INSN_SEQ_LEN bytes of the function
+ * looking for each argument saving instruction we would expect to see.  We
+ * loop byte-by-byte, rather than doing anything smart about insn lengths,
+ * only deviating from this when we know we have our insn, and can skip the
+ * rest of it.
+ *
+ * If there are odd number of arguments to a function, additional space is
+ * reserved on the stack to maintain 16-byte alignment.  For example,
+ *
+ *     argc == 0: no argument saving.
+ *     argc == 3: save 3, but space for 4 is reserved
+ *     argc == 7: save 6.
+ */
+
+#include <sys/sysmacros.h>
+#include <sys/types.h>
+#include <saveargs.h>
+
+/*
+ * Size of the instruction sequence arrays.  It should correspond to
+ * the maximum number of arguments passed via registers.
+ */
+#define	INSTR_ARRAY_SIZE	6
+
+#define	INSTR1(ins, off) (ins[(off)])
+#define	INSTR2(ins, off) (ins[(off)] + (ins[(off) + 1] << 8))
+#define	INSTR3(ins, off)	\
+	(ins[(off)] + (ins[(off) + 1] << 8) + (ins[(off + 2)] << 16))
+#define	INSTR4(ins, off)	\
+	(ins[(off)] + (ins[(off) + 1] << 8) + (ins[(off + 2)] << 16) + \
+	(ins[(off) + 3] << 24))
+
+/*
+ * Sun Studio 10 patch implementation saves %rdi first;
+ * GCC 3.4.3 Sun branch implementation saves them in reverse order.
+ */
+static const uint32_t save_instr[INSTR_ARRAY_SIZE] = {
+	0xf87d8948,	/* movq %rdi, -0x8(%rbp) */
+	0xf0758948,	/* movq %rsi, -0x10(%rbp) */
+	0xe8558948,	/* movq %rdx, -0x18(%rbp) */
+	0xe04d8948,	/* movq %rcx, -0x20(%rbp) */
+	0xd845894c,	/* movq %r8, -0x28(%rbp) */
+	0xd04d894c	/* movq %r9, -0x30(%rbp) */
+};
+
+static const uint16_t save_instr_push[] = {
+	0x57,	/* pushq %rdi */
+	0x56,	/* pushq %rsi */
+	0x52,	/* pushq %rdx */
+	0x51,	/* pushq %rcx */
+	0x5041,	/* pushq %r8 */
+	0x5141	/* pushq %r9 */
+};
+
+/*
+ * If the return type of a function is a structure greater than 16 bytes in
+ * size, %rdi will contain the address to which it should be stored, and
+ * arguments will begin at %rsi.  Studio will push all of the normal argument
+ * registers anyway, GCC will start pushing at %rsi, so we need a separate
+ * pattern.
+ */
+static const uint32_t save_instr_sr[INSTR_ARRAY_SIZE-1] = {
+	0xf8758948,	/* movq %rsi,-0x8(%rbp) */
+	0xf0558948,	/* movq %rdx,-0x10(%rbp) */
+	0xe84d8948,	/* movq %rcx,-0x18(%rbp) */
+	0xe045894c,	/* movq %r8,-0x20(%rbp) */
+	0xd84d894c	/* movq %r9,-0x28(%rbp) */
+};
+
+static const uint8_t save_fp_pushes[] = {
+    0x55,	/* pushq %rbp */
+    0xcc	/* int $0x3 */
+};
+#define	NUM_FP_PUSHES (sizeof (save_fp_pushes) / sizeof (save_fp_pushes[0]))
+
+static const uint32_t save_fp_movs[] = {
+	0x00e58948,	/* movq %rsp,%rbp, encoding 1 */
+	0x00ec8b48,	/* movq %rsp,%rbp, encoding 2 */
+};
+#define	NUM_FP_MOVS (sizeof (save_fp_movs) / sizeof (save_fp_movs[0]))
+
+static int
+has_saved_fp(uint8_t *ins, int size)
+{
+	int i, j;
+	uint32_t n;
+	int found_push = 0;
+
+	for (i = 0; i < size; i++) {
+		if (found_push == 0) {
+			n = INSTR1(ins, i);
+			for (j = 0; j <= NUM_FP_PUSHES; j++)
+				if (save_fp_pushes[j] == n) {
+					found_push = 1;
+					break;
+				}
+		} else {
+			n = INSTR3(ins, i);
+			for (j = 0; j <= NUM_FP_MOVS; j++)
+				if (save_fp_movs[j] == n)
+					return (1);
+		}
+	}
+
+	return (0);
+}
+
+int
+saveargs_has_args(uint8_t *ins, size_t size, uint_t argc, int start_index)
+{
+	int		i, j;
+	uint32_t	n;
+
+	argc = MIN((start_index + argc), INSTR_ARRAY_SIZE);
+
+	if (!has_saved_fp(ins, size))
+		return (SAVEARGS_NO_ARGS);
+
+	/*
+	 * Compare against Sun Studio implementation
+	 */
+	for (i = 4, j = 0; i <= size - 4; i++) {
+		n = INSTR4(ins, i);
+
+		if (n == save_instr[j]) {
+			i += 3;
+			if (++j >= argc)
+				return (start_index ? SAVEARGS_STRUCT_ARGS :
+				    SAVEARGS_TRAD_ARGS);
+		}
+	}
+
+	/*
+	 * Compare against GCC implementation
+	 */
+	for (i = 4, j = argc - 1; i <= size - 4; i++) {
+		n = INSTR4(ins, i);
+
+		if (n == save_instr[j]) {
+			i += 3;
+			if (--j < start_index)
+				return (SAVEARGS_TRAD_ARGS);
+		}
+	}
+
+	/*
+	 * Compare against GCC push-based implementation
+	 */
+	for (i = 4, j = start_index; i <= size - 2; i += 1) {
+		n = (i >= (8 - start_index)) ? INSTR2(ins, i) : INSTR1(ins, i);
+
+		if (n == save_instr_push[j]) {
+			if (i >= (8 - start_index))
+				i += 1;
+			if (++j >= argc)
+				return (SAVEARGS_TRAD_ARGS);
+		}
+	}
+
+	/* Look for a GCC-style returned structure */
+	if (start_index != 0) {
+		for (i = 4, j = argc - 2; i <= size - 4; i++) {
+			n = INSTR4(ins, i);
+
+			if (n == save_instr_sr[j]) {
+				i += 3;
+				if (--j >= (argc - 1))
+					return (SAVEARGS_TRAD_ARGS);
+			}
+		}
+	}
+
+	return (SAVEARGS_NO_ARGS);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/saveargs/saveargs.h	Fri Sep 07 23:51:24 2012 -0400
@@ -0,0 +1,52 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_SAVEARGS_H
+#define	_SAVEARGS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+/*
+ * The longest instruction sequence in bytes before all 6 arguments are
+ * saved on the stack.  This value depends on compiler implementation,
+ * therefore it should be examined periodically to guarantee accuracy.
+ */
+#define	SAVEARGS_INSN_SEQ_LEN	256
+
+#define	SAVEARGS_NO_ARGS	0	/* no saved arguments */
+#define	SAVEARGS_TRAD_ARGS	1	/* traditionally located arguments */
+#define	SAVEARGS_STRUCT_ARGS	2	/* struct return addr pushed as arg0 */
+
+int saveargs_has_args(uint8_t *, size_t, uint_t, int);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif	/* _SAVEARGS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/saveargs/tests/README	Fri Sep 07 23:51:24 2012 -0400
@@ -0,0 +1,9 @@
+testmatch:
+
+   A stub program that tests the saveargs matcher against a variety of
+   function prologues (assembled from data.s)
+
+functional:
+
+   Actually test the full chunk of the (libproc) side of the code, running
+   pstack on the range of test apps.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/saveargs/tests/functional/Makefile	Fri Sep 07 23:51:24 2012 -0400
@@ -0,0 +1,45 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2012, Richard Lowe.
+#
+
+include $(SRC)/Makefile.master
+include $(SRC)/Makefile.master.64
+
+.KEEP_STATE:
+
+PROGS = align \
+	basic \
+	big-struct-ret \
+	big-struct-ret-and-spill \
+	small-struct-ret \
+	small-struct-ret-and-spill \
+	stack-spill
+
+CFLAGS += $(CTF_FLAGS)
+CFLAGS64 += $(CTF_FLAGS)
+
+%: %.c
+	$(LINK.c) -o $@ $< -lc
+	$(CTFCONVERT) -L VERSION $@
+
+all: $(PROGS)
+
+install: all
+
+clean:
+	$(RM) $(PROGS)
+
+clobber: clean
+
+FRC:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/saveargs/tests/functional/align.c	Fri Sep 07 23:51:24 2012 -0400
@@ -0,0 +1,32 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2012, Richard Lowe.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+int
+test(long a, long b, long c, long d, long e)
+{
+	printf("%ld %ld %ld %ld %ld\n", a, b, c, d, e);
+	for (;;)
+		sleep(60);
+}
+
+int
+main(int argc, char **argv)
+{
+	test(1, 2, 3, 4, 5);
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/saveargs/tests/functional/basic.c	Fri Sep 07 23:51:24 2012 -0400
@@ -0,0 +1,32 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2012, Richard Lowe.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+int
+test(long a, long b, long c, long d)
+{
+	printf("%ld %ld %ld %ld\n", a, b, c, d);
+	for (;;)
+		sleep(60);
+}
+
+int
+main(int argc, char **argv)
+{
+	test(1, 2, 3, 4);
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/saveargs/tests/functional/big-struct-ret-and-spill.c	Fri Sep 07 23:51:24 2012 -0400
@@ -0,0 +1,38 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2012, Richard Lowe.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+struct foo {
+	long a;
+	long b;
+	long c;
+};
+
+struct foo
+test(long a, long b, long c, long d, long e, long f, long g, long h)
+{
+	printf("%ld %ld %ld %ld %ld %ld %ld %ld\n", a, b, c, d, e, f, g, h);
+	for (;;)
+		sleep(60);
+}
+
+int
+main(int argc, char **argv)
+{
+	test(1, 2, 3, 4, 5, 6, 7, 8);
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/saveargs/tests/functional/big-struct-ret.c	Fri Sep 07 23:51:24 2012 -0400
@@ -0,0 +1,38 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2012, Richard Lowe.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+struct foo {
+	long a;
+	long b;
+	long c;
+};
+
+struct foo
+test(long a, long b, long c, long d)
+{
+	printf("%ld %ld %ld %ld\n", a, b, c, d);
+	for (;;)
+		sleep(60);
+}
+
+int
+main(int argc, char **argv)
+{
+	test(1, 2, 3, 4);
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/saveargs/tests/functional/small-struct-ret-and-spill.c	Fri Sep 07 23:51:24 2012 -0400
@@ -0,0 +1,37 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2012, Richard Lowe.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+struct foo {
+	long a;
+	long b;
+};
+
+struct foo
+test(long a, long b, long c, long d, long e, long f, long g, long h)
+{
+	printf("%ld %ld %ld %ld %ld %ld %ld %ld\n", a, b, c, d, e, f, g, h);
+	for (;;)
+		sleep(60);
+}
+
+int
+main(int argc, char **argv)
+{
+	test(1, 2, 3, 4, 5, 6, 7, 8);
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/saveargs/tests/functional/small-struct-ret.c	Fri Sep 07 23:51:24 2012 -0400
@@ -0,0 +1,37 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2012, Richard Lowe.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+struct foo {
+	long a;
+	long b;
+};
+
+struct foo
+test(long a, long b, long c, long d)
+{
+	printf("%ld %ld %ld %ld\n", a, b, c, d);
+	for (;;)
+		sleep(60);
+}
+
+int
+main(int argc, char **argv)
+{
+	test(1, 2, 3, 4);
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/saveargs/tests/functional/stack-spill.c	Fri Sep 07 23:51:24 2012 -0400
@@ -0,0 +1,32 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2012, Richard Lowe.
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+int
+test(long a, long b, long c, long d, long e, long f, long g, long h)
+{
+	printf("%ld %ld %ld %ld %ld %ld %ld %ld\n", a, b, c, d, e, f, g, h);
+	for (;;)
+		sleep(60);
+}
+
+int
+main(int argc, char **argv)
+{
+	test(1, 2, 3, 4, 5, 6, 7, 8);
+	return (0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/saveargs/tests/functional/test.sh	Fri Sep 07 23:51:24 2012 -0400
@@ -0,0 +1,37 @@
+#! /usr/bin/ksh
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2012, Richard Lowe.
+#
+
+function tester {
+    prog=${1}
+    pattern=${2}
+
+    ./$prog >/dev/null &
+    pid=$!
+    if (/usr/bin/amd64/pstack $pid | /usr/xpg4/bin/grep -q "${pattern}"); then
+        echo "pass: ${prog}"
+    else
+        echo "FAIL: ${prog}"
+    fi
+    kill $pid
+}
+
+tester align "test (1, 2, 3, 4, 5)"
+tester basic "test (1, 2, 3, 4)"
+tester big-struct-ret "test (1, 2, 3, 4)"
+tester big-struct-ret-and-spill "test (1, 2, 3, 4, 5, 6, 7, 8)"
+tester small-struct-ret "test (1, 2, 3, 4)"
+tester small-struct-ret-and-spill "test (1, 2, 3, 4, 5, 6, 7, 8)"
+tester stack-spill "test (1, 2, 3, 4, 5, 6, 7, 8)"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/saveargs/tests/testmatch/Makefile	Fri Sep 07 23:51:24 2012 -0400
@@ -0,0 +1,41 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright 2012, Richard Lowe.
+#
+
+include $(SRC)/Makefile.master
+include $(SRC)/Makefile.master.64
+
+.KEEP_STATE:
+
+OBJECTS = testmatch.o saveargs.o data.o
+PROG = testmatch
+
+CPPFLAGS += -I$(SRC)/common/saveargs
+ASFLAGS += -P
+AS_CPPFLAGS += -D_ASM
+
+%.o: $(SRC)/common/saveargs/%.c
+	$(COMPILE.c) -o $@ $<
+
+$(PROG): $(OBJECTS)
+	$(LINK.c) -o $@ $(OBJECTS) -lc
+
+clean:
+	$(RM) $(OBJECTS) $(PROG)
+
+clobber: clean
+
+all: $(PROG)
+
+install: all
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/saveargs/tests/testmatch/data.s	Fri Sep 07 23:51:24 2012 -0400
@@ -0,0 +1,396 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2012, Richard Lowe.
+ */
+
+#define	FUNC(x) \
+	.text; \
+	.align	16; \
+	.globl	x; \
+	.type	x, @function; \
+x:
+
+#define	SET_SIZE(x, x_size) \
+	.size	x, [.-x]; \
+        .globl x_size; \
+        .type  x_size, @object; \
+x_size:
+
+/*
+ * Extracted versions of the functional tests
+ *
+ * Named of the form <compiler>-<prologue style>-<nature of test>
+ * basic			-- A regular function
+ * align			-- odd number of arguments needing save-area
+ * 				   alignment
+ * big-struct-ret		-- returns a > 16byte structure by value
+ * big-struct-ret-and-spill	-- returns a > 16byte structure by value and
+ * 				   spills args to the stack
+ * small-struct-ret		-- returns a < 16byte structure by value
+ * small-struct-ret-and-spill	-- returns a < 16byte structure by value and
+ * 				   spills args to the stack
+ * stack-spill			-- spills arguments to the stack
+ */
+FUNC(gcc_mov_align)
+pushq	%rbp
+movq	%rsp, %rbp
+movq	%rbx, -0x38(%rbp)
+movq	%r8, -0x28(%rbp)
+movq	%rcx, -0x20(%rbp)
+movq	%rdx, -0x18(%rbp)
+movq	%rsi, -0x10(%rbp)
+movq	%rdi, -0x8(%rbp)
+subq	$0x70, %rsp
+SET_SIZE(gcc_mov_align, gcc_mov_align_end)
+
+FUNC(gcc_mov_basic)
+pushq	%rbp
+movq	%rsp, %rbp
+movq	%rbx,-0x28(%rbp)
+movq    %rcx,-0x20(%rbp)
+movq    %rdx,-0x18(%rbp)
+movq    %rsi,-0x10(%rbp)
+movq    %rdi,-0x8(%rbp)
+subq    $0x50,%rsp
+SET_SIZE(gcc_mov_basic, gcc_mov_basic_end)
+
+FUNC(gcc_mov_big_struct_ret)
+pushq   %rbp
+movq    %rsp,%rbp
+movq    %rbx,-0x28(%rbp)
+movq    %r8,-0x20(%rbp)
+movq    %rcx,-0x18(%rbp)
+movq    %rdx,-0x10(%rbp)
+movq    %rsi,-0x8(%rbp)
+subq    $0x50,%rsp
+SET_SIZE(gcc_mov_big_struct_ret, gcc_mov_big_struct_ret_end)
+
+FUNC(gcc_mov_big_struct_ret_and_spill)
+pushq   %rbp
+movq    %rsp,%rbp
+movq    %rbx,-0x38(%rbp)
+movq    %r9,-0x28(%rbp)
+movq    %r8,-0x20(%rbp)
+movq    %rcx,-0x18(%rbp)
+movq    %rdx,-0x10(%rbp)
+movq    %rsi,-0x8(%rbp)
+subq    $0x90,%rsp
+SET_SIZE(gcc_mov_big_struct_ret_and_spill, gcc_mov_big_struct_ret_and_spill_end)
+
+FUNC(gcc_mov_small_struct_ret)
+pushq   %rbp
+movq    %rsp,%rbp
+movq    %rbx,-0x28(%rbp)
+movq    %rcx,-0x20(%rbp)
+movq    %rdx,-0x18(%rbp)
+movq    %rsi,-0x10(%rbp)
+movq    %rdi,-0x8(%rbp)
+subq    $0x50,%rsp
+SET_SIZE(gcc_mov_small_struct_ret, gcc_mov_small_struct_ret_end)
+
+FUNC(gcc_mov_small_struct_ret_and_spill)
+pushq   %rbp
+movq    %rsp,%rbp
+movq    %rbx,-0x38(%rbp)
+movq    %r9,-0x30(%rbp)
+movq    %r8,-0x28(%rbp)
+movq    %rcx,-0x20(%rbp)
+movq    %rdx,-0x18(%rbp)
+movq    %rsi,-0x10(%rbp)
+movq    %rdi,-0x8(%rbp)
+subq    $0x90,%rsp
+SET_SIZE(gcc_mov_small_struct_ret_and_spill, gcc_mov_small_struct_ret_and_spill_end)
+
+FUNC(gcc_mov_stack_spill)
+pushq   %rbp
+movq    %rsp,%rbp
+movq    %rbx,-0x38(%rbp)
+movq    %r9,-0x30(%rbp)
+movq    %r8,-0x28(%rbp)
+movq    %rcx,-0x20(%rbp)
+movq    %rdx,-0x18(%rbp)
+movq    %rsi,-0x10(%rbp)
+movq    %rdi,-0x8(%rbp)
+subq    $0x90,%rsp
+SET_SIZE(gcc_mov_stack_spill, gcc_mov_stack_spill_end)
+
+FUNC(gcc_push_align)
+pushq   %rbp
+movq    %rsp,%rbp
+pushq   %rdi
+pushq   %rsi
+pushq   %rdx
+pushq   %rcx
+pushq   %r8
+subq    $0x8,%rsp
+subq    $0x30,%rsp
+SET_SIZE(gcc_push_align, gcc_push_align_end)
+
+FUNC(gcc_push_basic)
+pushq   %rbp
+movq    %rsp,%rbp
+pushq   %rdi
+pushq   %rsi
+pushq   %rdx
+pushq   %rcx
+subq    $0x20,%rsp
+SET_SIZE(gcc_push_basic, gcc_push_basic_end)
+
+FUNC(gcc_push_big_struct_ret)
+pushq   %rbp
+movq    %rsp,%rbp
+pushq   %rsi
+pushq   %rdx
+pushq   %rcx
+pushq   %r8
+subq    $0x30,%rsp
+SET_SIZE(gcc_push_big_struct_ret, gcc_push_big_struct_ret_end)
+
+FUNC(gcc_push_big_struct_ret_and_spill)
+pushq   %rbp
+movq    %rsp,%rbp
+pushq   %rsi
+pushq   %rdx
+pushq   %rcx
+pushq   %r8
+pushq   %r9
+subq    $0x8,%rsp
+subq    $0x50,%rsp
+SET_SIZE(gcc_push_big_struct_ret_and_spill, gcc_push_big_struct_ret_and_spill_end)
+
+FUNC(gcc_push_small_struct_ret)
+pushq   %rbp
+movq    %rsp,%rbp
+pushq   %rdi
+pushq   %rsi
+pushq   %rdx
+pushq   %rcx
+subq    $0x20,%rsp
+SET_SIZE(gcc_push_small_struct_ret, gcc_push_small_struct_ret_end)
+
+FUNC(gcc_push_small_struct_ret_and_spill)
+pushq   %rbp
+movq    %rsp,%rbp
+pushq   %rdi
+pushq   %rsi
+pushq   %rdx
+pushq   %rcx
+pushq   %r8
+pushq   %r9
+subq    $0x50,%rsp
+SET_SIZE(gcc_push_small_struct_ret_and_spill, gcc_push_small_struct_ret_and_spill_end)
+
+FUNC(gcc_push_stack_spill)
+pushq   %rbp
+movq    %rsp,%rbp
+pushq   %rdi
+pushq   %rsi
+pushq   %rdx
+pushq   %rcx
+pushq   %r8
+pushq   %r9
+subq    $0x50,%rsp
+SET_SIZE(gcc_push_stack_spill, gcc_push_stack_spill_end)
+
+FUNC(ss_mov_align)
+pushq   %rbp
+movq    %rsp,%rbp
+subq    $0x30,%rsp
+movq    %rdi,-0x8(%rbp)
+movq    %rsi,-0x10(%rbp)
+movq    %rdx,-0x18(%rbp)
+movq    %rcx,-0x20(%rbp)
+movq    %r8,-0x28(%rbp)
+SET_SIZE(ss_mov_align, ss_mov_align_end)
+
+FUNC(ss_mov_basic)
+pushq   %rbp
+movq    %rsp,%rbp
+subq    $0x20,%rsp
+movq    %rdi,-0x8(%rbp)
+movq    %rsi,-0x10(%rbp)
+movq    %rdx,-0x18(%rbp)
+movq    %rcx,-0x20(%rbp)
+SET_SIZE(ss_mov_basic, ss_mov_basic_end)
+
+FUNC(ss_mov_big_struct_ret)
+pushq   %rbp
+movq    %rsp,%rbp
+subq    $0x30,%rsp
+movq    %rdi,-0x8(%rbp)
+movq    %rsi,-0x10(%rbp)
+movq    %rdx,-0x18(%rbp)
+movq    %rcx,-0x20(%rbp)
+movq    %r8,-0x28(%rbp)
+SET_SIZE(ss_mov_big_struct_ret, ss_mov_big_struct_ret_end)
+
+FUNC(ss_mov_big_struct_ret_and_spill)
+pushq   %rbp
+movq    %rsp,%rbp
+subq    $0x50,%rsp
+movq    %rdi,-0x8(%rbp)
+movq    %rsi,-0x10(%rbp)
+movq    %rdx,-0x18(%rbp)
+movq    %rcx,-0x20(%rbp)
+movq    %r8,-0x28(%rbp)
+movq    %r9,-0x30(%rbp)
+SET_SIZE(ss_mov_big_struct_ret_and_spill, ss_mov_big_struct_ret_and_spill_end)
+
+FUNC(ss_mov_small_struct_ret)
+pushq   %rbp
+movq    %rsp,%rbp
+subq    $0x20,%rsp
+movq    %rdi,-0x8(%rbp)
+movq    %rsi,-0x10(%rbp)
+movq    %rdx,-0x18(%rbp)
+movq    %rcx,-0x20(%rbp)
+SET_SIZE(ss_mov_small_struct_ret, ss_mov_small_struct_ret_end)
+
+FUNC(ss_mov_small_struct_ret_and_spill)
+pushq   %rbp
+movq    %rsp,%rbp
+subq    $0x50,%rsp
+movq    %rdi,-0x8(%rbp)
+movq    %rsi,-0x10(%rbp)
+movq    %rdx,-0x18(%rbp)
+movq    %rcx,-0x20(%rbp)
+movq    %r8,-0x28(%rbp)
+movq    %r9,-0x30(%rbp)
+SET_SIZE(ss_mov_small_struct_ret_and_spill, ss_mov_small_struct_ret_and_spill_end)
+
+FUNC(ss_mov_stack_spill)
+pushq   %rbp
+movq    %rsp,%rbp
+subq    $0x50,%rsp
+movq    %rdi,-0x8(%rbp)
+movq    %rsi,-0x10(%rbp)
+movq    %rdx,-0x18(%rbp)
+movq    %rcx,-0x20(%rbp)
+movq    %r8,-0x28(%rbp)
+movq    %r9,-0x30(%rbp)
+SET_SIZE(ss_mov_stack_spill, ss_mov_stack_spill_end)
+
+/* DTrace instrumentation */
+FUNC(dtrace_instrumented)
+int	$0x3
+movq	%rsp, %rbp
+movq	%rbx,-0x28(%rbp)
+movq    %rcx,-0x20(%rbp)
+movq    %rdx,-0x18(%rbp)
+movq    %rsi,-0x10(%rbp)
+movq    %rdi,-0x8(%rbp)
+subq    $0x50,%rsp
+SET_SIZE(dtrace_instrumented, dtrace_instrumented_end)
+
+/*
+ * System functions with special characteristics, be they non-initial FP save,
+ * gaps between FP save and argument saving, or gaps between saved arguments.
+ */
+FUNC(kmem_alloc)
+leaq    -0x1(%rdi),%rax
+pushq   %rbp
+movq    %rax,%rdx
+movq    %rsp,%rbp
+subq    $0x30,%rsp
+shrq    $0x3,%rdx
+movq    %r12,-0x28(%rbp)
+movq    %rbx,-0x30(%rbp)
+cmpq    $0x1ff,%rdx
+movq    %r13,-0x20(%rbp)
+movq    %r14,-0x18(%rbp)
+movq    %rsi,-0x10(%rbp)
+movq    %rdi,-0x8(%rbp)
+movq    %rdi,%r12
+SET_SIZE(kmem_alloc, kmem_alloc_end)
+
+FUNC(uts_kill)
+pushq   %rbp
+movq    %rsp,%rbp
+subq    $0x50,%rsp
+movq    %rbx,-0x28(%rbp)
+leaq    -0x50(%rbp),%rbx
+movq    %r12,-0x20(%rbp)
+movq    %r13,-0x18(%rbp)
+movq    %rsi,-0x10(%rbp)
+movl    %edi,%r12d
+movq    %rdi,-0x8(%rbp)
+SET_SIZE(uts_kill, uts_kill_end)
+
+FUNC(av1394_ic_bitreverse)
+movq    %rdi,%rdx
+movq    $0x5555555555555555,%rax
+movq    $0x3333333333333333,%rcx
+shrq    $0x1,%rdx
+pushq   %rbp
+andq    %rax,%rdx
+andq    %rdi,%rax
+addq    %rax,%rax
+movq    %rsp,%rbp
+subq    $0x10,%rsp
+orq     %rdx,%rax
+movq    %rdi,-0x8(%rbp)
+SET_SIZE(av1394_ic_bitreverse, av1394_ic_bitreverse_end)
+
+/* Problematic functions which should not match */
+
+FUNC(no_fp) /* No frame pointer */
+movq	%rdi, %rsi
+movq	%rsi, %rdi
+movq	%rbx,-0x28(%rbp)
+movq    %rcx,-0x20(%rbp)
+movq    %rdx,-0x18(%rbp)
+movq    %rsi,-0x10(%rbp)
+movq    %rdi,-0x8(%rbp)
+subq    $0x50,%rsp
+SET_SIZE(no_fp, no_fp_end)
+
+/* Small structure return, but with an SSE type (thus forcing it to the stack) */
+FUNC(small_struct_ret_w_float)
+pushq   %rbp
+movq    %rsp,%rbp
+movq    %rdi,-0x8(%rbp)
+subq    $0x30,%rsp
+SET_SIZE(small_struct_ret_w_float, small_struct_ret_w_float_end)
+
+/* Big structure return, but with an SSE type */
+FUNC(big_struct_ret_w_float)
+pushq  %rbp
+movq   %rsp,%rbp
+movq   %rsi,-0x8(%rbp)
+subq   $0x50,%rsp
+movq   %rsi,-0x48(%rbp)
+movq   -0x48(%rbp),%rax
+movq   %rax,%rsi
+movl   $0x400f60,%edi
+movl   $0x0,%eax
+movl   $0x1770,%edi
+movl   $0x0,%eax
+leave
+ret
+SET_SIZE(big_struct_ret_w_float, big_struct_ret_w_float_end)
+
+FUNC(big_struct_arg_by_value)
+pushq   %rbp
+movq    %rsp,%rbp
+movq    %rdi,-0x8(%rbp)
+subq    $0x40,%rsp
+SET_SIZE(big_struct_arg_by_value, big_struct_arg_by_value_end)
+
+FUNC(small_struct_arg_by_value)
+pushq   %rbp
+movq    %rsp,%rbp
+movq    %rdx,-0x18(%rbp)
+movq    %rsi,-0x10(%rbp)
+movq    %rdi,-0x8(%rbp)
+subq    $0x50,%rsp
+SET_SIZE(small_struct_arg_by_value, small_struct_arg_by_value_end)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/common/saveargs/tests/testmatch/testmatch.c	Fri Sep 07 23:51:24 2012 -0400
@@ -0,0 +1,137 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy of the CDDL is also available via the Internet at
+ * http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2012, Richard Lowe.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <saveargs.h>
+
+#define	DEF_TEST(name)		\
+    extern uint8_t name[];	\
+    extern int name##_end
+
+#define	SIZE_OF(name) ((caddr_t)&name##_end - (caddr_t)&name)
+
+#define	TEST_GOOD(name, argc)					\
+    if (saveargs_has_args(name, SIZE_OF(name), argc, 0) != 0)	\
+	printf("Pass: %s\n", #name);				\
+    else							\
+	printf("FAIL: %s\n", #name);
+
+#define	TEST_GOOD_STRUCT(name, argc)				\
+    if (saveargs_has_args(name, SIZE_OF(name), argc, 1) != 0)	\
+	printf("Pass: %s\n", #name);				\
+    else							\
+	printf("FAIL: %s\n", #name);
+
+#define	TEST_BAD(name, argc)					\
+    if (saveargs_has_args(name, SIZE_OF(name), argc, 0) == 0)	\
+	printf("Pass: %s\n", #name);				\
+    else							\
+	printf("FAIL: %s\n", #name);
+
+#define	TEST_BAD_STRUCT(name, argc)				\
+    if (saveargs_has_args(name, SIZE_OF(name), argc, 1) == 0)	\
+	printf("Pass: %s\n", #name);				\
+    else							\
+	printf("FAIL: %s\n", #name);
+
+DEF_TEST(gcc_mov_align);
+DEF_TEST(gcc_mov_basic);
+DEF_TEST(gcc_mov_big_struct_ret);
+DEF_TEST(gcc_mov_big_struct_ret_and_spill);
+DEF_TEST(gcc_mov_small_struct_ret);
+DEF_TEST(gcc_mov_small_struct_ret_and_spill);
+DEF_TEST(gcc_mov_stack_spill);
+
+DEF_TEST(gcc_push_align);
+DEF_TEST(gcc_push_basic);
+DEF_TEST(gcc_push_big_struct_ret);
+DEF_TEST(gcc_push_big_struct_ret_and_spill);
+DEF_TEST(gcc_push_small_struct_ret);
+DEF_TEST(gcc_push_small_struct_ret_and_spill);
+DEF_TEST(gcc_push_stack_spill);
+
+DEF_TEST(ss_mov_align);
+DEF_TEST(ss_mov_basic);
+DEF_TEST(ss_mov_big_struct_ret);
+DEF_TEST(ss_mov_big_struct_ret_and_spill);
+DEF_TEST(ss_mov_small_struct_ret);
+DEF_TEST(ss_mov_small_struct_ret_and_spill);
+DEF_TEST(ss_mov_stack_spill);
+
+DEF_TEST(dtrace_instrumented);
+DEF_TEST(kmem_alloc);
+DEF_TEST(uts_kill);
+DEF_TEST(av1394_ic_bitreverse);
+
+DEF_TEST(small_struct_ret_w_float);
+DEF_TEST(big_struct_ret_w_float);
+
+/*
+ * Functions which should not match
+ *
+ * no_fp			-- valid save-args sequence with no saved FP
+ * big_struct_arg_by_value	-- function with big struct passed by value
+ * small_struct_arg_by_value	-- function with small struct passed by value
+ */
+DEF_TEST(no_fp);
+DEF_TEST(big_struct_arg_by_value);
+DEF_TEST(small_struct_arg_by_value);
+
+int
+main(int argc, char **argv)
+{
+	TEST_GOOD(kmem_alloc, 2);
+	TEST_GOOD(uts_kill, 2);
+	TEST_GOOD(av1394_ic_bitreverse, 1);
+	TEST_GOOD(dtrace_instrumented, 4);
+	TEST_GOOD_STRUCT(big_struct_ret_w_float, 1);
+	TEST_BAD(no_fp, 5);
+
+	TEST_GOOD(gcc_mov_align, 5);
+	TEST_GOOD(gcc_push_align, 5);
+	TEST_GOOD(ss_mov_align, 5);
+
+	TEST_GOOD(gcc_mov_basic, 4);
+	TEST_GOOD(gcc_push_basic, 4);
+	TEST_GOOD(ss_mov_basic, 4);
+
+	TEST_GOOD_STRUCT(gcc_mov_big_struct_ret, 4);
+	TEST_GOOD_STRUCT(gcc_push_big_struct_ret, 4);
+	TEST_GOOD_STRUCT(ss_mov_big_struct_ret, 4);
+
+	TEST_GOOD_STRUCT(gcc_mov_big_struct_ret_and_spill, 8);
+	TEST_GOOD_STRUCT(gcc_push_big_struct_ret_and_spill, 8);
+	TEST_GOOD_STRUCT(ss_mov_big_struct_ret_and_spill, 8);
+
+	TEST_GOOD(gcc_mov_small_struct_ret, 4);
+	TEST_GOOD(gcc_push_small_struct_ret, 4);
+	TEST_GOOD(ss_mov_small_struct_ret, 4);
+
+	TEST_GOOD(gcc_mov_small_struct_ret_and_spill, 8);
+	TEST_GOOD(gcc_push_small_struct_ret_and_spill, 8);
+	TEST_GOOD(ss_mov_small_struct_ret_and_spill, 8);
+
+	TEST_GOOD(gcc_mov_stack_spill, 8);
+	TEST_GOOD(gcc_push_stack_spill, 8);
+	TEST_GOOD(ss_mov_stack_spill, 8);
+
+	TEST_BAD(big_struct_arg_by_value, 2);
+	TEST_BAD(small_struct_arg_by_value, 2);
+
+	TEST_BAD(small_struct_ret_w_float, 1);
+
+	return (0);
+}
--- a/usr/src/lib/libproc/Makefile.com	Thu Oct 18 16:38:42 2012 +0000
+++ b/usr/src/lib/libproc/Makefile.com	Fri Sep 07 23:51:24 2012 -0400
@@ -72,7 +72,14 @@
 ISAOBJS =	\
 	Pisadep.o
 
-OBJECTS = $(CMNOBJS) $(ISAOBJS)
+amd64_SAVEOBJS = \
+	saveargs.o
+
+amd64_CPPFLAGS = -I$(SRC)/common/saveargs
+
+SAVEOBJS = $($(MACH64)_SAVEOBJS)
+
+OBJECTS = $(CMNOBJS) $(ISAOBJS) $(SAVEOBJS)
 
 # include library definitions
 include ../../Makefile.lib
@@ -82,6 +89,7 @@
 
 LIBS =		$(DYNLIB) $(LINTLIB)
 LDLIBS +=	-lrtld_db -lelf -lctf -lc
+CPPFLAGS +=	$($(MACH64)_CPPFLAGS)
 
 SRCDIR =	../common
 $(LINTLIB) :=	SRCS = $(SRCDIR)/$(LINTSRC)
@@ -113,3 +121,7 @@
 objs/%.o pics/%.o: %.c
 	$(COMPILE.c) -o $@ $<
 	$(POST_PROCESS_O)
+
+objs/%.o pics/%.o: $(SRC)/common/saveargs/%.c
+	$(COMPILE.c) -o $@ $<
+	$(POST_PROCESS_O)
--- a/usr/src/lib/libproc/amd64/Pisadep.c	Thu Oct 18 16:38:42 2012 +0000
+++ b/usr/src/lib/libproc/amd64/Pisadep.c	Fri Sep 07 23:51:24 2012 -0400
@@ -36,6 +36,7 @@
 #include <errno.h>
 #include <string.h>
 
+#include <saveargs.h>
 #include "Pcontrol.h"
 #include "Pstack.h"
 
@@ -346,6 +347,121 @@
 	(void) memcpy(dst, src->uc_mcontext.gregs, sizeof (gregset_t));
 }
 
+/*
+ * Read arguments from the frame indicated by regs into args, return the
+ * number of arguments successfully read
+ */
+static int
+read_args(struct ps_prochandle *P, uintptr_t fp, uintptr_t pc, prgreg_t *args,
+    size_t argsize)
+{
+	GElf_Sym sym;
+	ctf_file_t *ctfp = NULL;
+	ctf_funcinfo_t finfo;
+	prsyminfo_t si = {0};
+	uint8_t ins[SAVEARGS_INSN_SEQ_LEN];
+	size_t insnsize;
+	int argc = 0;
+	int rettype = 0;
+	int start_index = 0;
+	int args_style = 0;
+	int i;
+	ctf_id_t args_types[5];
+
+	if (Pxlookup_by_addr(P, pc, NULL, 0, &sym, &si) != 0)
+		return (0);
+
+	if ((ctfp = Paddr_to_ctf(P, pc)) == NULL)
+		return (0);
+
+	if (ctf_func_info(ctfp, si.prs_id, &finfo) == CTF_ERR)
+		return (0);
+
+	argc = finfo.ctc_argc;
+
+	if (argc == 0)
+		return (0);
+
+	rettype = ctf_type_kind(ctfp, finfo.ctc_return);
+
+	/*
+	 * If the function returns a structure or union greater than 16 bytes
+	 * in size %rdi contains the address in which to store the return
+	 * value rather than for an argument.
+	 */
+	if (((rettype == CTF_K_STRUCT) || (rettype == CTF_K_UNION)) &&
+	    ctf_type_size(ctfp, finfo.ctc_return) > 16)
+		start_index = 1;
+	else
+		start_index = 0;
+
+	/*
+	 * If any of the first 5 arguments are a structure less than 16 bytes
+	 * in size, it will be passed spread across two argument registers,
+	 * and we will not cope.
+	 */
+	if (ctf_func_args(ctfp, si.prs_id, 5, args_types) == CTF_ERR)
+		return (0);
+
+	for (i = 0; i < MIN(5, finfo.ctc_argc); i++) {
+		int t = ctf_type_kind(ctfp, args_types[i]);
+
+		if (((t == CTF_K_STRUCT) || (t == CTF_K_UNION)) &&
+		    ctf_type_size(ctfp, args_types[i]) <= 16)
+			return (0);
+	}
+
+	/*
+	 * The number of instructions to search for argument saving is limited
+	 * such that only instructions prior to %pc are considered and we
+	 * never read arguments from a function where the saving code has not
+	 * in fact yet executed.
+	 */
+	insnsize = MIN(MIN(sym.st_size, SAVEARGS_INSN_SEQ_LEN),
+	    pc - sym.st_value);
+
+	if (Pread(P, ins, insnsize, sym.st_value) != insnsize)
+		return (0);
+
+	if ((argc != 0) &&
+	    ((args_style = saveargs_has_args(ins, insnsize, argc,
+	    start_index)) != SAVEARGS_NO_ARGS)) {
+		int regargs = MIN((6 - start_index), argc);
+		size_t size = regargs * sizeof (long);
+		int i;
+
+		/*
+		 * If Studio pushed a structure return address as an argument,
+		 * we need to read one more argument than actually exists (the
+		 * addr) to make everything line up.
+		 */
+		if (args_style == SAVEARGS_STRUCT_ARGS)
+			size += sizeof (long);
+
+		if (Pread(P, args, size, (fp - size)) != size)
+			return (0);
+
+		for (i = 0; i < (regargs / 2); i++) {
+			prgreg_t t = args[i];
+
+			args[i] = args[regargs - i - 1];
+			args[regargs - i - 1] = t;
+		}
+
+		if (argc > regargs) {
+			size = MIN((argc - regargs) * sizeof (long),
+			    argsize - (regargs * sizeof (long)));
+
+			if (Pread(P, &args[regargs], size, fp +
+			    (sizeof (uintptr_t) * 2)) != size)
+				return (6);
+		}
+
+		return (argc);
+	} else {
+		return (0);
+	}
+}
 
 int
 Pstack_iter(struct ps_prochandle *P, const prgregset_t regs,
@@ -381,7 +497,7 @@
 		prgreg_t signo;
 		siginfo_t *sip;
 	} sigframe_t;
-	prgreg_t args[32];
+	prgreg_t args[32] = {0};
 
 	if (P->status.pr_dmodel != PR_MODEL_LP64)
 		return (Pstack_iter32(P, regs, func, arg));
@@ -400,20 +516,16 @@
 		if (fp != 0 &&
 		    Pread(P, &frame, sizeof (frame), (uintptr_t)fp) ==
 		    sizeof (frame)) {
-
-			if (frame.pc != -1) {
-				/*
-				 * Function arguments are not available on
-				 * amd64 without extensive DWARF processing.
-				 */
-				argc = 0;
-			} else {
+			if (frame.pc == -1) {
 				argc = 3;
 				args[2] = fp + sizeof (sigframe_t);
 				if (Pread(P, &args, 2 * sizeof (prgreg_t),
 				    fp + 2 * sizeof (prgreg_t)) !=
 				    2 * sizeof (prgreg_t))
 					argc = 0;
+			} else {
+				argc = read_args(P, fp, pc, args,
+				    sizeof (args));
 			}
 		} else {
 			(void) memset(&frame, 0, sizeof (frame));
--- a/usr/src/tools/findunref/exception_list.open	Thu Oct 18 16:38:42 2012 +0000
+++ b/usr/src/tools/findunref/exception_list.open	Fri Sep 07 23:51:24 2012 -0400
@@ -132,6 +132,7 @@
 ./usr/src/lib/crypt_modules/sha256/test.c
 ./usr/src/lib/efcode/fcode_test
 ./usr/src/lib/libkvm/common/test.c
+./usr/src/common/saveargs/tests/
 
 #
 # Ignore debugging code.
--- a/usr/src/uts/Makefile.uts	Thu Oct 18 16:38:42 2012 +0000
+++ b/usr/src/uts/Makefile.uts	Fri Sep 07 23:51:24 2012 -0400
@@ -231,7 +231,7 @@
 CFLAGS_uts		+= $(CCVERBOSE)
 CFLAGS_uts		+= $(ILDOFF)
 CFLAGS_uts		+= $(XAOPT)
-CFLAGS_uts		+= $(CTF_FLAGS)
+CFLAGS_uts		+= $(CTF_FLAGS_$(CLASS))
 CFLAGS_uts		+= $(CERRWARN)
 CFLAGS_uts		+= $(CCNOAUTOINLINE)
 CFLAGS_uts		+= $(CGLOBALSTATIC)
--- a/usr/src/uts/sparc/Makefile.sparc.shared	Thu Oct 18 16:38:42 2012 +0000
+++ b/usr/src/uts/sparc/Makefile.sparc.shared	Fri Sep 07 23:51:24 2012 -0400
@@ -131,7 +131,7 @@
 CFLAGS		+= $(CCMODE)
 CFLAGS		+= $(SPACEFLAG)
 CFLAGS		+= $(CERRWARN)
-CFLAGS		+= $(CTF_FLAGS)
+CFLAGS		+= $(CTF_FLAGS_$(CLASS))
 CFLAGS		+= $(C99MODE)
 CFLAGS		+= $(CCUNBOUND)
 CFLAGS		+= $(CCSTATICSYM)
--- a/usr/src/uts/sun4u/Makefile.sun4u.shared	Thu Oct 18 16:38:42 2012 +0000
+++ b/usr/src/uts/sun4u/Makefile.sun4u.shared	Fri Sep 07 23:51:24 2012 -0400
@@ -205,7 +205,7 @@
 CFLAGS		+= $(CCMODE)
 CFLAGS		+= $(SPACEFLAG)
 CFLAGS		+= $(CERRWARN)
-CFLAGS		+= $(CTF_FLAGS)
+CFLAGS		+= $(CTF_FLAGS_$(CLASS))
 CFLAGS		+= $(C99MODE)
 CFLAGS		+= $(CCUNBOUND)
 CFLAGS		+= $(CCNOAUTOINLINE)
--- a/usr/src/uts/sun4v/Makefile.sun4v.shared	Thu Oct 18 16:38:42 2012 +0000
+++ b/usr/src/uts/sun4v/Makefile.sun4v.shared	Fri Sep 07 23:51:24 2012 -0400
@@ -179,7 +179,7 @@
 CFLAGS		+= $(CCMODE)
 CFLAGS		+= $(SPACEFLAG)
 CFLAGS		+= $(CERRWARN)
-CFLAGS		+= $(CTF_FLAGS)
+CFLAGS		+= $(CTF_FLAGS_$(CLASS))
 CFLAGS		+= $(C99MODE)
 CFLAGS		+= $(CCUNBOUND)
 CFLAGS		+= $(CCNOAUTOINLINE)