Mercurial > illumos > illumos-gate
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>
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)