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