Home | History | Annotate | Download | only in mdb
      1     0   stevel /*
      2     0   stevel  * CDDL HEADER START
      3     0   stevel  *
      4     0   stevel  * The contents of this file are subject to the terms of the
      5  2244    dmick  * Common Development and Distribution License (the "License").
      6  2244    dmick  * You may not use this file except in compliance with the License.
      7     0   stevel  *
      8     0   stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0   stevel  * or http://www.opensolaris.org/os/licensing.
     10     0   stevel  * See the License for the specific language governing permissions
     11     0   stevel  * and limitations under the License.
     12     0   stevel  *
     13     0   stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0   stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0   stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0   stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0   stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0   stevel  *
     19     0   stevel  * CDDL HEADER END
     20     0   stevel  */
     21  2244    dmick 
     22     0   stevel /*
     23  3446      mrj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     24     0   stevel  * Use is subject to license terms.
     25     0   stevel  */
     26     0   stevel 
     27     0   stevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28     0   stevel 
     29     0   stevel #include <sys/types.h>
     30     0   stevel #include <sys/reg.h>
     31     0   stevel #include <sys/privregs.h>
     32     0   stevel #include <sys/stack.h>
     33     0   stevel #include <sys/frame.h>
     34     0   stevel 
     35     0   stevel #include <mdb/mdb_target_impl.h>
     36     0   stevel #include <mdb/mdb_kreg_impl.h>
     37     0   stevel #include <mdb/mdb_debug.h>
     38     0   stevel #include <mdb/mdb_modapi.h>
     39     0   stevel #include <mdb/mdb_amd64util.h>
     40   170  sherrym #include <mdb/mdb_ctf.h>
     41     0   stevel #include <mdb/mdb_err.h>
     42     0   stevel #include <mdb/mdb.h>
     43     0   stevel 
     44     0   stevel /*
     45     0   stevel  * This array is used by the getareg and putareg entry points, and also by our
     46     0   stevel  * register variable discipline.
     47     0   stevel  */
     48     0   stevel 
     49     0   stevel const mdb_tgt_regdesc_t mdb_amd64_kregs[] = {
     50     0   stevel 	{ "savfp", KREG_SAVFP, MDB_TGT_R_EXPORT },
     51     0   stevel 	{ "savpc", KREG_SAVPC, MDB_TGT_R_EXPORT },
     52     0   stevel 	{ "rdi", KREG_RDI, MDB_TGT_R_EXPORT },
     53     0   stevel 	{ "rsi", KREG_RSI, MDB_TGT_R_EXPORT },
     54     0   stevel 	{ "rdx", KREG_RDX, MDB_TGT_R_EXPORT },
     55     0   stevel 	{ "rcx", KREG_RCX, MDB_TGT_R_EXPORT },
     56     0   stevel 	{ "r8", KREG_R8, MDB_TGT_R_EXPORT },
     57     0   stevel 	{ "r9", KREG_R9, MDB_TGT_R_EXPORT },
     58     0   stevel 	{ "rax", KREG_RAX, MDB_TGT_R_EXPORT },
     59     0   stevel 	{ "rbx", KREG_RBX, MDB_TGT_R_EXPORT },
     60     0   stevel 	{ "rbp", KREG_RBP, MDB_TGT_R_EXPORT },
     61     0   stevel 	{ "r10", KREG_R10, MDB_TGT_R_EXPORT },
     62     0   stevel 	{ "r11", KREG_R11, MDB_TGT_R_EXPORT },
     63     0   stevel 	{ "r12", KREG_R12, MDB_TGT_R_EXPORT },
     64     0   stevel 	{ "r13", KREG_R13, MDB_TGT_R_EXPORT },
     65     0   stevel 	{ "r14", KREG_R14, MDB_TGT_R_EXPORT },
     66     0   stevel 	{ "r15", KREG_R15, MDB_TGT_R_EXPORT },
     67     0   stevel 	{ "ds", KREG_DS, MDB_TGT_R_EXPORT },
     68     0   stevel 	{ "es", KREG_ES, MDB_TGT_R_EXPORT },
     69     0   stevel 	{ "fs", KREG_FS, MDB_TGT_R_EXPORT },
     70     0   stevel 	{ "gs", KREG_GS, MDB_TGT_R_EXPORT },
     71     0   stevel 	{ "trapno", KREG_TRAPNO, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
     72     0   stevel 	{ "err", KREG_ERR, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
     73     0   stevel 	{ "rip", KREG_RIP, MDB_TGT_R_EXPORT },
     74     0   stevel 	{ "cs", KREG_CS, MDB_TGT_R_EXPORT },
     75     0   stevel 	{ "rflags", KREG_RFLAGS, MDB_TGT_R_EXPORT },
     76     0   stevel 	{ "rsp", KREG_RSP, MDB_TGT_R_EXPORT },
     77     0   stevel 	{ "ss", KREG_SS, MDB_TGT_R_EXPORT },
     78     0   stevel 	{ NULL, 0, 0 }
     79     0   stevel };
     80     0   stevel 
     81     0   stevel void
     82     0   stevel mdb_amd64_printregs(const mdb_tgt_gregset_t *gregs)
     83     0   stevel {
     84     0   stevel 	const kreg_t *kregs = &gregs->kregs[0];
     85     0   stevel 	kreg_t rflags = kregs[KREG_RFLAGS];
     86     0   stevel 
     87     0   stevel #define	GETREG2(x) ((uintptr_t)kregs[(x)]), ((uintptr_t)kregs[(x)])
     88     0   stevel 
     89     0   stevel 	mdb_printf("%%rax = 0x%0?p %15A %%r9  = 0x%0?p %A\n",
     90     0   stevel 	    GETREG2(KREG_RAX), GETREG2(KREG_R9));
     91     0   stevel 	mdb_printf("%%rbx = 0x%0?p %15A %%r10 = 0x%0?p %A\n",
     92     0   stevel 	    GETREG2(KREG_RBX), GETREG2(KREG_R10));
     93     0   stevel 	mdb_printf("%%rcx = 0x%0?p %15A %%r11 = 0x%0?p %A\n",
     94     0   stevel 	    GETREG2(KREG_RCX), GETREG2(KREG_R11));
     95     0   stevel 	mdb_printf("%%rdx = 0x%0?p %15A %%r12 = 0x%0?p %A\n",
     96     0   stevel 	    GETREG2(KREG_RDX), GETREG2(KREG_R12));
     97     0   stevel 	mdb_printf("%%rsi = 0x%0?p %15A %%r13 = 0x%0?p %A\n",
     98     0   stevel 	    GETREG2(KREG_RSI), GETREG2(KREG_R13));
     99     0   stevel 	mdb_printf("%%rdi = 0x%0?p %15A %%r14 = 0x%0?p %A\n",
    100     0   stevel 	    GETREG2(KREG_RDI), GETREG2(KREG_R14));
    101     0   stevel 	mdb_printf("%%r8  = 0x%0?p %15A %%r15 = 0x%0?p %A\n\n",
    102     0   stevel 	    GETREG2(KREG_R8), GETREG2(KREG_R15));
    103     0   stevel 
    104     0   stevel 	mdb_printf("%%rip = 0x%0?p %A\n", GETREG2(KREG_RIP));
    105     0   stevel 	mdb_printf("%%rbp = 0x%0?p\n", kregs[KREG_RBP]);
    106     0   stevel 	mdb_printf("%%rsp = 0x%0?p\n", kregs[KREG_RSP]);
    107     0   stevel 
    108     0   stevel 	mdb_printf("%%rflags = 0x%08x\n", rflags);
    109     0   stevel 
    110     0   stevel 	mdb_printf("  id=%u vip=%u vif=%u ac=%u vm=%u rf=%u nt=%u iopl=0x%x\n",
    111     0   stevel 	    (rflags & KREG_EFLAGS_ID_MASK) >> KREG_EFLAGS_ID_SHIFT,
    112     0   stevel 	    (rflags & KREG_EFLAGS_VIP_MASK) >> KREG_EFLAGS_VIP_SHIFT,
    113     0   stevel 	    (rflags & KREG_EFLAGS_VIF_MASK) >> KREG_EFLAGS_VIF_SHIFT,
    114     0   stevel 	    (rflags & KREG_EFLAGS_AC_MASK) >> KREG_EFLAGS_AC_SHIFT,
    115     0   stevel 	    (rflags & KREG_EFLAGS_VM_MASK) >> KREG_EFLAGS_VM_SHIFT,
    116     0   stevel 	    (rflags & KREG_EFLAGS_RF_MASK) >> KREG_EFLAGS_RF_SHIFT,
    117     0   stevel 	    (rflags & KREG_EFLAGS_NT_MASK) >> KREG_EFLAGS_NT_SHIFT,
    118     0   stevel 	    (rflags & KREG_EFLAGS_IOPL_MASK) >> KREG_EFLAGS_IOPL_SHIFT);
    119     0   stevel 
    120     0   stevel 	mdb_printf("  status=<%s,%s,%s,%s,%s,%s,%s,%s,%s>\n\n",
    121     0   stevel 	    (rflags & KREG_EFLAGS_OF_MASK) ? "OF" : "of",
    122     0   stevel 	    (rflags & KREG_EFLAGS_DF_MASK) ? "DF" : "df",
    123     0   stevel 	    (rflags & KREG_EFLAGS_IF_MASK) ? "IF" : "if",
    124     0   stevel 	    (rflags & KREG_EFLAGS_TF_MASK) ? "TF" : "tf",
    125     0   stevel 	    (rflags & KREG_EFLAGS_SF_MASK) ? "SF" : "sf",
    126     0   stevel 	    (rflags & KREG_EFLAGS_ZF_MASK) ? "ZF" : "zf",
    127     0   stevel 	    (rflags & KREG_EFLAGS_AF_MASK) ? "AF" : "af",
    128     0   stevel 	    (rflags & KREG_EFLAGS_PF_MASK) ? "PF" : "pf",
    129     0   stevel 	    (rflags & KREG_EFLAGS_CF_MASK) ? "CF" : "cf");
    130     0   stevel 
    131     0   stevel 	mdb_printf("%24s%%cs = 0x%04x\t%%ds = 0x%04x\t%%es = 0x%04x\n",
    132     0   stevel 	    " ", kregs[KREG_CS], kregs[KREG_DS], kregs[KREG_ES]);
    133     0   stevel 
    134  3446      mrj 	mdb_printf("%%trapno = 0x%x\t\t%%fs = 0x%04x\t%%gs = 0x%04x\n",
    135  3446      mrj 	    kregs[KREG_TRAPNO], (kregs[KREG_FS] & 0xffff),
    136  3446      mrj 	    (kregs[KREG_GS] & 0xffff));
    137  3446      mrj 	mdb_printf("   %%err = 0x%x\n", kregs[KREG_ERR]);
    138     0   stevel }
    139   170  sherrym 
    140   170  sherrym /*
    141   170  sherrym  * Sun Studio 10 patch compiler and gcc 3.4.3 Sun branch implemented a
    142   170  sherrym  * "-save_args" option on amd64.  When the option is specified, INTEGER
    143   170  sherrym  * type function arguments passed via registers will be saved on the stack
    144   170  sherrym  * immediately after %rbp, and will not be modified through out the life
    145   170  sherrym  * of the routine.
    146   170  sherrym  *
    147   170  sherrym  *				+--------+
    148   170  sherrym  *		%rbp	-->     |  %rbp  |
    149   170  sherrym  *				+--------+
    150   170  sherrym  *		-0x8(%rbp)	|  %rdi  |
    151   170  sherrym  *				+--------+
    152   170  sherrym  *		-0x10(%rbp)	|  %rsi  |
    153   170  sherrym  *				+--------+
    154   170  sherrym  *		-0x18(%rbp)	|  %rdx  |
    155   170  sherrym  *				+--------+
    156   170  sherrym  *		-0x20(%rbp)	|  %rcx  |
    157   170  sherrym  *				+--------+
    158   170  sherrym  *		-0x28(%rbp)	|  %r8   |
    159   170  sherrym  *				+--------+
    160   170  sherrym  *		-0x30(%rbp)	|  %r9   |
    161   170  sherrym  *				+--------+
    162   170  sherrym  *
    163   170  sherrym  *
    164   170  sherrym  * For example, for the following function,
    165   170  sherrym  *
    166   170  sherrym  * void
    167   170  sherrym  * foo(int a1, int a2, int a3, int a4, int a5, int a6, int a7)
    168   170  sherrym  * {
    169   170  sherrym  * ...
    170   170  sherrym  * }
    171   170  sherrym  *
    172   170  sherrym  * Disassembled code will look something like the following:
    173   170  sherrym  *
    174   170  sherrym  *     pushq	%rbp
    175   170  sherrym  *     movq	%rsp, %rbp
    176   170  sherrym  *     subq	$imm8, %rsp			**
    177   170  sherrym  *     movq	%rdi, -0x8(%rbp)
    178   170  sherrym  *     movq	%rsi, -0x10(%rbp)
    179   170  sherrym  *     movq	%rdx, -0x18(%rbp)
    180   170  sherrym  *     movq	%rcx, -0x20(%rbp)
    181   170  sherrym  *     movq	%r8, -0x28(%rbp)
    182   170  sherrym  *     movq	%r9, -0x30(%rbp)
    183   170  sherrym  *     ...
    184   170  sherrym  * or
    185   170  sherrym  *     pushq	%rbp
    186   170  sherrym  *     movq	%rsp, %rbp
    187   170  sherrym  *     subq	$imm8, %rsp			**
    188   170  sherrym  *     movq	%r9, -0x30(%rbp)
    189   170  sherrym  *     movq	%r8, -0x28(%rbp)
    190   170  sherrym  *     movq	%rcx, -0x20(%rbp)
    191   170  sherrym  *     movq	%rdx, -0x18(%rbp)
    192   170  sherrym  *     movq	%rsi, -0x10(%rbp)
    193   170  sherrym  *     movq	%rdi, -0x8(%rbp)
    194   170  sherrym  *     ...
    195   170  sherrym  *
    196   170  sherrym  * **: The space being reserved is in addition to what the current
    197   170  sherrym  *     function prolog already reserves.
    198   170  sherrym  *
    199   170  sherrym  * If there are odd number of arguments to a function, additional space is
    200   170  sherrym  * reserved on the stack to maintain 16-byte alignment.  For example,
    201   170  sherrym  *
    202   170  sherrym  *     argc == 0: no argument saving.
    203   170  sherrym  *     argc == 3: save 3, but space for 4 is reserved
    204   170  sherrym  *     argc == 7: save 6.
    205   170  sherrym  */
    206   170  sherrym 
    207   170  sherrym /*
    208   170  sherrym  * The longest instruction sequence in bytes before all 6 arguments are
    209   170  sherrym  * saved on the stack.  This value depends on compiler implementation,
    210   170  sherrym  * therefore it should be examined periodically to guarantee accuracy.
    211   170  sherrym  */
    212   170  sherrym #define	SEQ_LEN		80
    213   170  sherrym 
    214   170  sherrym /*
    215   170  sherrym  * Size of the instruction sequence arrays.  It should correspond to
    216   170  sherrym  * the maximum number of arguments passed via registers.
    217   170  sherrym  */
    218   170  sherrym #define	INSTR_ARRAY_SIZE	6
    219   170  sherrym 
    220   170  sherrym #define	INSTR4(ins, off)	\
    221   170  sherrym 	(ins[(off)] + (ins[(off) + 1] << 8) + (ins[(off + 2)] << 16) + \
    222   170  sherrym 	(ins[(off) + 3] << 24))
    223   170  sherrym 
    224   170  sherrym /*
    225   170  sherrym  * Sun Studio 10 patch implementation saves %rdi first;
    226   170  sherrym  * GCC 3.4.3 Sun branch implementation saves them in reverse order.
    227   170  sherrym  */
    228   170  sherrym static const uint32_t save_instr[INSTR_ARRAY_SIZE] = {
    229   170  sherrym 	0xf87d8948,	/* movq %rdi, -0x8(%rbp) */
    230   170  sherrym 	0xf0758948,	/* movq %rsi, -0x10(%rbp) */
    231   170  sherrym 	0xe8558948,	/* movq %rdx, -0x18(%rbp) */
    232   170  sherrym 	0xe04d8948,	/* movq %rcx, -0x20(%rbp) */
    233   170  sherrym 	0xd845894c,	/* movq %r8, -0x28(%rbp) */
    234   170  sherrym 	0xd04d894c	/* movq %r9, -0x30(%rbp) */
    235   170  sherrym };
    236   170  sherrym 
    237   275  sherrym static const uint32_t save_fp_instr[] = {
    238   170  sherrym 	0xe5894855,	/* pushq %rbp; movq %rsp,%rbp, encoding 1 */
    239   275  sherrym 	0xec8b4855,	/* pushq %rbp; movq %rsp,%rbp, encoding 2 */
    240   275  sherrym 	0xe58948cc,	/* int $0x3; movq %rsp,%rbp, encoding 1 */
    241   275  sherrym 	0xec8b48cc,	/* int $0x3; movq %rsp,%rbp, encoding 2 */
    242   275  sherrym 	NULL
    243   170  sherrym };
    244   170  sherrym 
    245   170  sherrym /*
    246   170  sherrym  * Look for the above instruction sequences as indicators for register
    247   170  sherrym  * arguments being available on the stack.
    248   170  sherrym  */
    249   170  sherrym static int
    250   170  sherrym is_argsaved(mdb_tgt_t *t, uintptr_t fstart, uint64_t size, uint_t argc,
    251   170  sherrym     int start_index)
    252   170  sherrym {
    253   170  sherrym 	uint8_t		ins[SEQ_LEN];
    254   170  sherrym 	int		i, j;
    255   170  sherrym 	uint32_t	n;
    256   170  sherrym 
    257   170  sherrym 	size = MIN(size, SEQ_LEN);
    258   170  sherrym 	argc = MIN((start_index + argc), INSTR_ARRAY_SIZE);
    259   170  sherrym 
    260   170  sherrym 	if (mdb_tgt_vread(t, ins, size, fstart) != size)
    261   170  sherrym 		return (0);
    262   170  sherrym 
    263   170  sherrym 	/*
    264   170  sherrym 	 * Make sure framepointer has been saved.
    265   170  sherrym 	 */
    266   170  sherrym 	n = INSTR4(ins, 0);
    267   275  sherrym 	for (i = 0; save_fp_instr[i] != NULL; i++) {
    268   170  sherrym 		if (n == save_fp_instr[i])
    269   170  sherrym 			break;
    270   170  sherrym 	}
    271   170  sherrym 
    272   275  sherrym 	if (save_fp_instr[i] == NULL)
    273   170  sherrym 		return (0);
    274   170  sherrym 
    275   170  sherrym 	/*
    276   170  sherrym 	 * Compare against Sun Studio implementation
    277   170  sherrym 	 */
    278   170  sherrym 	for (i = 8, j = start_index; i < size - 4; i++) {
    279   170  sherrym 		n = INSTR4(ins, i);
    280   170  sherrym 
    281   170  sherrym 		if (n == save_instr[j]) {
    282   170  sherrym 			i += 3;
    283   170  sherrym 			if (++j >= argc)
    284   170  sherrym 				return (1);
    285   170  sherrym 		}
    286   170  sherrym 	}
    287   170  sherrym 
    288   170  sherrym 	/*
    289   170  sherrym 	 * Compare against GCC implementation
    290   170  sherrym 	 */
    291   170  sherrym 	for (i = 8, j = argc - 1; i < size - 4; i++) {
    292   170  sherrym 		n = INSTR4(ins, i);
    293   170  sherrym 
    294   170  sherrym 		if (n == save_instr[j]) {
    295   170  sherrym 			i += 3;
    296   170  sherrym 			if (--j < start_index)
    297   170  sherrym 				return (1);
    298   170  sherrym 		}
    299   170  sherrym 	}
    300   170  sherrym 
    301   170  sherrym 	return (0);
    302   170  sherrym }
    303   170  sherrym 
    304  5084  johnlev /*
    305  5084  johnlev  * We expect all proper Solaris core files to have STACK_ALIGN-aligned stacks.
    306  5084  johnlev  * Hence the name.  However, if the core file resulted from a
    307  5084  johnlev  * hypervisor-initiated panic, the hypervisor's frames may only be 64-bit
    308  5084  johnlev  * aligned instead of 128.
    309  5084  johnlev  */
    310  5084  johnlev static int
    311  5084  johnlev fp_is_aligned(uintptr_t fp, int xpv_panic)
    312  5084  johnlev {
    313  5084  johnlev 	if (!xpv_panic && (fp & (STACK_ALIGN -1)))
    314  5084  johnlev 		return (0);
    315  5084  johnlev 	if ((fp & sizeof (uintptr_t) - 1))
    316  5084  johnlev 		return (0);
    317  5084  johnlev 	return (1);
    318  5084  johnlev }
    319  5084  johnlev 
    320     0   stevel int
    321     0   stevel mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
    322     0   stevel     mdb_tgt_stack_f *func, void *arg)
    323     0   stevel {
    324     0   stevel 	mdb_tgt_gregset_t gregs;
    325     0   stevel 	kreg_t *kregs = &gregs.kregs[0];
    326     0   stevel 	int got_pc = (gsp->kregs[KREG_RIP] != 0);
    327   170  sherrym 	uint_t argc, reg_argc;
    328   170  sherrym 	long fr_argv[32];
    329   170  sherrym 	int start_index; /* index to save_instr where to start comparison */
    330   170  sherrym 	int i;
    331     0   stevel 
    332     0   stevel 	struct {
    333     0   stevel 		uintptr_t fr_savfp;
    334     0   stevel 		uintptr_t fr_savpc;
    335     0   stevel 	} fr;
    336     0   stevel 
    337     0   stevel 	uintptr_t fp = gsp->kregs[KREG_RBP];
    338     0   stevel 	uintptr_t pc = gsp->kregs[KREG_RIP];
    339  5084  johnlev 	uintptr_t lastfp, curpc;
    340   170  sherrym 
    341   170  sherrym 	ssize_t size;
    342   170  sherrym 
    343   170  sherrym 	GElf_Sym s;
    344   170  sherrym 	mdb_syminfo_t sip;
    345   170  sherrym 	mdb_ctf_funcinfo_t mfp;
    346  5084  johnlev 	int xpv_panic = 0;
    347  5084  johnlev #ifndef	_KMDB
    348  5084  johnlev 	int xp;
    349  5084  johnlev 
    350  5084  johnlev 	if ((mdb_readsym(&xp, sizeof (xp), "xpv_panicking") != -1) && (xp > 0))
    351  5084  johnlev 		xpv_panic = 1;
    352  5084  johnlev #endif
    353     0   stevel 
    354     0   stevel 	bcopy(gsp, &gregs, sizeof (gregs));
    355     0   stevel 
    356     0   stevel 	while (fp != 0) {
    357     0   stevel 
    358   170  sherrym 		curpc = pc;
    359   170  sherrym 
    360  5084  johnlev 		if (!fp_is_aligned(fp, xpv_panic))
    361     0   stevel 			return (set_errno(EMDB_STKALIGN));
    362     0   stevel 
    363   170  sherrym 		if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) != sizeof (fr))
    364   170  sherrym 			return (-1);	/* errno has been set for us */
    365     0   stevel 
    366   170  sherrym 		if ((mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY,
    367   170  sherrym 		    NULL, 0, &s, &sip) == 0) &&
    368   170  sherrym 		    (mdb_ctf_func_info(&s, &sip, &mfp) == 0)) {
    369   170  sherrym 			int return_type = mdb_ctf_type_kind(mfp.mtf_return);
    370   170  sherrym 			argc = mfp.mtf_argc;
    371   170  sherrym 			/*
    372   170  sherrym 			 * If the function returns a structure or union,
    373   170  sherrym 			 * %rdi contains the address in which to store the
    374   170  sherrym 			 * return value rather than for an argument.
    375   170  sherrym 			 */
    376   170  sherrym 			if (return_type == CTF_K_STRUCT ||
    377   170  sherrym 			    return_type == CTF_K_UNION)
    378   170  sherrym 				start_index = 1;
    379   170  sherrym 			else
    380   170  sherrym 				start_index = 0;
    381   170  sherrym 		} else {
    382   170  sherrym 			argc = 0;
    383   170  sherrym 		}
    384   170  sherrym 
    385   170  sherrym 		if (argc != 0 && is_argsaved(t, s.st_value, s.st_size,
    386   170  sherrym 		    argc, start_index)) {
    387   170  sherrym 
    388   170  sherrym 			/* Upto to 6 arguments are passed via registers */
    389   170  sherrym 			reg_argc = MIN(6, mfp.mtf_argc);
    390   170  sherrym 			size = reg_argc * sizeof (long);
    391   170  sherrym 
    392   170  sherrym 			if (mdb_tgt_vread(t, fr_argv, size, (fp - size))
    393   170  sherrym 			    != size)
    394   170  sherrym 				return (-1);	/* errno has been set for us */
    395   170  sherrym 
    396   170  sherrym 			/*
    397   170  sherrym 			 * Arrange the arguments in the right order for
    398   170  sherrym 			 * printing.
    399   170  sherrym 			 */
    400   170  sherrym 			for (i = 0; i < (reg_argc >> 1); i++) {
    401   170  sherrym 				long t = fr_argv[i];
    402   170  sherrym 
    403   170  sherrym 				fr_argv[i] = fr_argv[reg_argc - i - 1];
    404   170  sherrym 				fr_argv[reg_argc - i - 1] = t;
    405   170  sherrym 			}
    406   170  sherrym 
    407   170  sherrym 			if (argc > 6) {
    408   170  sherrym 				size = (argc - 6) * sizeof (long);
    409   170  sherrym 				if (mdb_tgt_vread(t, &fr_argv[6], size,
    410   170  sherrym 				    fp + sizeof (fr)) != size)
    411   170  sherrym 					return (-1); /* errno has been set */
    412   170  sherrym 			}
    413   170  sherrym 		} else
    414   170  sherrym 			argc = 0;
    415   170  sherrym 
    416   170  sherrym 		if (got_pc && func(arg, pc, argc, fr_argv, &gregs) != 0)
    417     0   stevel 			break;
    418     0   stevel 
    419     0   stevel 		kregs[KREG_RSP] = kregs[KREG_RBP];
    420     0   stevel 
    421  5084  johnlev 		lastfp = fp;
    422  5084  johnlev 		fp = fr.fr_savfp;
    423  5084  johnlev 		/*
    424  5084  johnlev 		 * The Xen hypervisor marks a stack frame as belonging to
    425  5084  johnlev 		 * an exception by inverting the bits of the pointer to
    426  5084  johnlev 		 * that frame.  We attempt to identify these frames by
    427  5084  johnlev 		 * inverting the pointer and seeing if it is within 0xfff
    428  5084  johnlev 		 * bytes of the last frame.
    429  5084  johnlev 		 */
    430  5084  johnlev 		if (xpv_panic)
    431  5084  johnlev 			if ((fp != 0) && (fp < lastfp) &&
    432  5084  johnlev 			    ((lastfp ^ ~fp) < 0xfff))
    433  5084  johnlev 			fp = ~fp;
    434  5084  johnlev 
    435  5084  johnlev 		kregs[KREG_RBP] = fp;
    436     0   stevel 		kregs[KREG_RIP] = pc = fr.fr_savpc;
    437   170  sherrym 
    438   170  sherrym 		if (curpc == pc)
    439   170  sherrym 			break;
    440     0   stevel 
    441     0   stevel 		got_pc = (pc != 0);
    442     0   stevel 	}
    443     0   stevel 
    444     0   stevel 	return (0);
    445     0   stevel }
    446     0   stevel 
    447     0   stevel /*
    448     0   stevel  * Determine the return address for the current frame.  Typically this is the
    449     0   stevel  * fr_savpc value from the current frame, but we also perform some special
    450     0   stevel  * handling to see if we are stopped on one of the first two instructions of
    451     0   stevel  * a typical function prologue, in which case %rbp will not be set up yet.
    452     0   stevel  */
    453     0   stevel int
    454     0   stevel mdb_amd64_step_out(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, kreg_t fp, kreg_t sp,
    455     0   stevel     mdb_instr_t curinstr)
    456     0   stevel {
    457     0   stevel 	struct frame fr;
    458     0   stevel 	GElf_Sym s;
    459     0   stevel 	char buf[1];
    460     0   stevel 
    461     0   stevel 	enum {
    462     0   stevel 		M_PUSHQ_RBP	= 0x55,	/* pushq %rbp */
    463     0   stevel 		M_REX_W		= 0x48, /* REX prefix with only W set */
    464     0   stevel 		M_MOVL_RBP	= 0x8b	/* movq %rsp, %rbp with prefix */
    465     0   stevel 	};
    466     0   stevel 
    467     0   stevel 	if (mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY,
    468     0   stevel 	    buf, 0, &s, NULL) == 0) {
    469     0   stevel 		if (pc == s.st_value && curinstr == M_PUSHQ_RBP)
    470     0   stevel 			fp = sp - 8;
    471     0   stevel 		else if (pc == s.st_value + 1 && curinstr == M_REX_W) {
    472     0   stevel 			if (mdb_tgt_vread(t, &curinstr, sizeof (curinstr),
    473     0   stevel 			    pc + 1) == sizeof (curinstr) && curinstr ==
    474     0   stevel 			    M_MOVL_RBP)
    475     0   stevel 				fp = sp;
    476     0   stevel 		}
    477     0   stevel 	}
    478     0   stevel 
    479     0   stevel 	if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) == sizeof (fr)) {
    480     0   stevel 		*p = fr.fr_savpc;
    481     0   stevel 		return (0);
    482     0   stevel 	}
    483     0   stevel 
    484     0   stevel 	return (-1); /* errno is set for us */
    485     0   stevel }
    486     0   stevel 
    487     0   stevel /*ARGSUSED*/
    488     0   stevel int
    489     0   stevel mdb_amd64_next(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, mdb_instr_t curinstr)
    490     0   stevel {
    491     0   stevel 	mdb_tgt_addr_t npc;
    492  2244    dmick 	mdb_tgt_addr_t callpc;
    493     0   stevel 
    494     0   stevel 	enum {
    495     0   stevel 		M_CALL_REL = 0xe8, /* call near with relative displacement */
    496     0   stevel 		M_CALL_REG = 0xff, /* call near indirect or call far register */
    497     0   stevel 
    498     0   stevel 		M_REX_LO = 0x40,
    499     0   stevel 		M_REX_HI = 0x4f
    500     0   stevel 	};
    501     0   stevel 
    502     0   stevel 	/*
    503     0   stevel 	 * If the opcode is a near call with relative displacement, assume the
    504     0   stevel 	 * displacement is a rel32 from the next instruction.
    505     0   stevel 	 */
    506     0   stevel 	if (curinstr == M_CALL_REL) {
    507     0   stevel 		*p = pc + sizeof (mdb_instr_t) + sizeof (uint32_t);
    508     0   stevel 		return (0);
    509     0   stevel 	}
    510     0   stevel 
    511     0   stevel 	/* Skip the rex prefix, if any */
    512  2244    dmick 	callpc = pc;
    513  2244    dmick 	while (curinstr >= M_REX_LO && curinstr <= M_REX_HI) {
    514  2244    dmick 		if (mdb_tgt_vread(t, &curinstr, sizeof (curinstr), ++callpc) !=
    515  2244    dmick 		    sizeof (curinstr))
    516  2244    dmick 			return (-1); /* errno is set for us */
    517  2244    dmick 	}
    518     0   stevel 
    519     0   stevel 	if (curinstr != M_CALL_REG) {
    520     0   stevel 		/* It's not a call */
    521     0   stevel 		return (set_errno(EAGAIN));
    522     0   stevel 	}
    523     0   stevel 
    524     0   stevel 	if ((npc = mdb_dis_nextins(mdb.m_disasm, t, MDB_TGT_AS_VIRT, pc)) == pc)
    525     0   stevel 		return (-1); /* errno is set for us */
    526     0   stevel 
    527     0   stevel 	*p = npc;
    528     0   stevel 	return (0);
    529     0   stevel }
    530     0   stevel 
    531     0   stevel /*ARGSUSED*/
    532     0   stevel int
    533     0   stevel mdb_amd64_kvm_frame(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
    534     0   stevel     const mdb_tgt_gregset_t *gregs)
    535     0   stevel {
    536     0   stevel 	argc = MIN(argc, (uintptr_t)arglim);
    537     0   stevel 	mdb_printf("%a(", pc);
    538     0   stevel 
    539     0   stevel 	if (argc != 0) {
    540     0   stevel 		mdb_printf("%lr", *argv++);
    541     0   stevel 		for (argc--; argc != 0; argc--)
    542     0   stevel 			mdb_printf(", %lr", *argv++);
    543     0   stevel 	}
    544     0   stevel 
    545     0   stevel 	mdb_printf(")\n");
    546     0   stevel 	return (0);
    547     0   stevel }
    548     0   stevel 
    549     0   stevel int
    550     0   stevel mdb_amd64_kvm_framev(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
    551     0   stevel     const mdb_tgt_gregset_t *gregs)
    552     0   stevel {
    553   170  sherrym 	/*
    554   170  sherrym 	 * Historically adb limited stack trace argument display to a fixed-
    555   170  sherrym 	 * size number of arguments since no symbolic debugging info existed.
    556   170  sherrym 	 * On amd64 we can detect the true number of saved arguments so only
    557   170  sherrym 	 * respect an arglim of zero; otherwise display the entire argv[].
    558   170  sherrym 	 */
    559   170  sherrym 	if (arglim == 0)
    560   170  sherrym 		argc = 0;
    561   170  sherrym 
    562     0   stevel 	mdb_printf("%0?lr %a(", gregs->kregs[KREG_RBP], pc);
    563     0   stevel 
    564     0   stevel 	if (argc != 0) {
    565     0   stevel 		mdb_printf("%lr", *argv++);
    566     0   stevel 		for (argc--; argc != 0; argc--)
    567     0   stevel 			mdb_printf(", %lr", *argv++);
    568     0   stevel 	}
    569     0   stevel 
    570     0   stevel 	mdb_printf(")\n");
    571     0   stevel 	return (0);
    572     0   stevel }
    573