xref: /onnv-gate/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c (revision 170:0c2980fdabb7)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <sys/types.h>
300Sstevel@tonic-gate #include <sys/reg.h>
310Sstevel@tonic-gate #include <sys/privregs.h>
320Sstevel@tonic-gate #include <sys/stack.h>
330Sstevel@tonic-gate #include <sys/frame.h>
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include <mdb/mdb_target_impl.h>
360Sstevel@tonic-gate #include <mdb/mdb_kreg_impl.h>
370Sstevel@tonic-gate #include <mdb/mdb_debug.h>
380Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
390Sstevel@tonic-gate #include <mdb/mdb_amd64util.h>
40*170Ssherrym #include <mdb/mdb_ctf.h>
410Sstevel@tonic-gate #include <mdb/mdb_err.h>
420Sstevel@tonic-gate #include <mdb/mdb.h>
430Sstevel@tonic-gate 
440Sstevel@tonic-gate /*
450Sstevel@tonic-gate  * This array is used by the getareg and putareg entry points, and also by our
460Sstevel@tonic-gate  * register variable discipline.
470Sstevel@tonic-gate  */
480Sstevel@tonic-gate 
490Sstevel@tonic-gate const mdb_tgt_regdesc_t mdb_amd64_kregs[] = {
500Sstevel@tonic-gate 	{ "savfp", KREG_SAVFP, MDB_TGT_R_EXPORT },
510Sstevel@tonic-gate 	{ "savpc", KREG_SAVPC, MDB_TGT_R_EXPORT },
520Sstevel@tonic-gate 	{ "rdi", KREG_RDI, MDB_TGT_R_EXPORT },
530Sstevel@tonic-gate 	{ "rsi", KREG_RSI, MDB_TGT_R_EXPORT },
540Sstevel@tonic-gate 	{ "rdx", KREG_RDX, MDB_TGT_R_EXPORT },
550Sstevel@tonic-gate 	{ "rcx", KREG_RCX, MDB_TGT_R_EXPORT },
560Sstevel@tonic-gate 	{ "r8", KREG_R8, MDB_TGT_R_EXPORT },
570Sstevel@tonic-gate 	{ "r9", KREG_R9, MDB_TGT_R_EXPORT },
580Sstevel@tonic-gate 	{ "rax", KREG_RAX, MDB_TGT_R_EXPORT },
590Sstevel@tonic-gate 	{ "rbx", KREG_RBX, MDB_TGT_R_EXPORT },
600Sstevel@tonic-gate 	{ "rbp", KREG_RBP, MDB_TGT_R_EXPORT },
610Sstevel@tonic-gate 	{ "r10", KREG_R10, MDB_TGT_R_EXPORT },
620Sstevel@tonic-gate 	{ "r11", KREG_R11, MDB_TGT_R_EXPORT },
630Sstevel@tonic-gate 	{ "r12", KREG_R12, MDB_TGT_R_EXPORT },
640Sstevel@tonic-gate 	{ "r13", KREG_R13, MDB_TGT_R_EXPORT },
650Sstevel@tonic-gate 	{ "r14", KREG_R14, MDB_TGT_R_EXPORT },
660Sstevel@tonic-gate 	{ "r15", KREG_R15, MDB_TGT_R_EXPORT },
670Sstevel@tonic-gate 	{ "fsbase", KREG_FSBASE, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
680Sstevel@tonic-gate 	{ "gsbase", KREG_GSBASE, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
690Sstevel@tonic-gate 	{ "kgsbase", KREG_KGSBASE, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
700Sstevel@tonic-gate 	{ "ds", KREG_DS, MDB_TGT_R_EXPORT },
710Sstevel@tonic-gate 	{ "es", KREG_ES, MDB_TGT_R_EXPORT },
720Sstevel@tonic-gate 	{ "fs", KREG_FS, MDB_TGT_R_EXPORT },
730Sstevel@tonic-gate 	{ "gs", KREG_GS, MDB_TGT_R_EXPORT },
740Sstevel@tonic-gate 	{ "trapno", KREG_TRAPNO, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
750Sstevel@tonic-gate 	{ "err", KREG_ERR, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
760Sstevel@tonic-gate 	{ "rip", KREG_RIP, MDB_TGT_R_EXPORT },
770Sstevel@tonic-gate 	{ "cs", KREG_CS, MDB_TGT_R_EXPORT },
780Sstevel@tonic-gate 	{ "rflags", KREG_RFLAGS, MDB_TGT_R_EXPORT },
790Sstevel@tonic-gate 	{ "rsp", KREG_RSP, MDB_TGT_R_EXPORT },
800Sstevel@tonic-gate 	{ "ss", KREG_SS, MDB_TGT_R_EXPORT },
810Sstevel@tonic-gate 	{ NULL, 0, 0 }
820Sstevel@tonic-gate };
830Sstevel@tonic-gate 
840Sstevel@tonic-gate void
850Sstevel@tonic-gate mdb_amd64_printregs(const mdb_tgt_gregset_t *gregs)
860Sstevel@tonic-gate {
870Sstevel@tonic-gate 	const kreg_t *kregs = &gregs->kregs[0];
880Sstevel@tonic-gate 	kreg_t rflags = kregs[KREG_RFLAGS];
890Sstevel@tonic-gate 
900Sstevel@tonic-gate #define	GETREG2(x) ((uintptr_t)kregs[(x)]), ((uintptr_t)kregs[(x)])
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 	mdb_printf("%%rax = 0x%0?p %15A %%r9  = 0x%0?p %A\n",
930Sstevel@tonic-gate 	    GETREG2(KREG_RAX), GETREG2(KREG_R9));
940Sstevel@tonic-gate 	mdb_printf("%%rbx = 0x%0?p %15A %%r10 = 0x%0?p %A\n",
950Sstevel@tonic-gate 	    GETREG2(KREG_RBX), GETREG2(KREG_R10));
960Sstevel@tonic-gate 	mdb_printf("%%rcx = 0x%0?p %15A %%r11 = 0x%0?p %A\n",
970Sstevel@tonic-gate 	    GETREG2(KREG_RCX), GETREG2(KREG_R11));
980Sstevel@tonic-gate 	mdb_printf("%%rdx = 0x%0?p %15A %%r12 = 0x%0?p %A\n",
990Sstevel@tonic-gate 	    GETREG2(KREG_RDX), GETREG2(KREG_R12));
1000Sstevel@tonic-gate 	mdb_printf("%%rsi = 0x%0?p %15A %%r13 = 0x%0?p %A\n",
1010Sstevel@tonic-gate 	    GETREG2(KREG_RSI), GETREG2(KREG_R13));
1020Sstevel@tonic-gate 	mdb_printf("%%rdi = 0x%0?p %15A %%r14 = 0x%0?p %A\n",
1030Sstevel@tonic-gate 	    GETREG2(KREG_RDI), GETREG2(KREG_R14));
1040Sstevel@tonic-gate 	mdb_printf("%%r8  = 0x%0?p %15A %%r15 = 0x%0?p %A\n\n",
1050Sstevel@tonic-gate 	    GETREG2(KREG_R8), GETREG2(KREG_R15));
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 	mdb_printf("%%rip = 0x%0?p %A\n", GETREG2(KREG_RIP));
1080Sstevel@tonic-gate 	mdb_printf("%%rbp = 0x%0?p\n", kregs[KREG_RBP]);
1090Sstevel@tonic-gate 	mdb_printf("%%rsp = 0x%0?p\n", kregs[KREG_RSP]);
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate 	mdb_printf("%%rflags = 0x%08x\n", rflags);
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 	mdb_printf("  id=%u vip=%u vif=%u ac=%u vm=%u rf=%u nt=%u iopl=0x%x\n",
1140Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_ID_MASK) >> KREG_EFLAGS_ID_SHIFT,
1150Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_VIP_MASK) >> KREG_EFLAGS_VIP_SHIFT,
1160Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_VIF_MASK) >> KREG_EFLAGS_VIF_SHIFT,
1170Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_AC_MASK) >> KREG_EFLAGS_AC_SHIFT,
1180Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_VM_MASK) >> KREG_EFLAGS_VM_SHIFT,
1190Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_RF_MASK) >> KREG_EFLAGS_RF_SHIFT,
1200Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_NT_MASK) >> KREG_EFLAGS_NT_SHIFT,
1210Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_IOPL_MASK) >> KREG_EFLAGS_IOPL_SHIFT);
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	mdb_printf("  status=<%s,%s,%s,%s,%s,%s,%s,%s,%s>\n\n",
1240Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_OF_MASK) ? "OF" : "of",
1250Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_DF_MASK) ? "DF" : "df",
1260Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_IF_MASK) ? "IF" : "if",
1270Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_TF_MASK) ? "TF" : "tf",
1280Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_SF_MASK) ? "SF" : "sf",
1290Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_ZF_MASK) ? "ZF" : "zf",
1300Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_AF_MASK) ? "AF" : "af",
1310Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_PF_MASK) ? "PF" : "pf",
1320Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_CF_MASK) ? "CF" : "cf");
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	mdb_printf("%24s%%cs = 0x%04x\t%%ds = 0x%04x\t%%es = 0x%04x\n",
1350Sstevel@tonic-gate 	    " ", kregs[KREG_CS], kregs[KREG_DS], kregs[KREG_ES]);
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 	mdb_printf("%%trapno = 0x%x\t\t%%fs = 0x%04x\tfsbase = 0x%0?p\n",
1380Sstevel@tonic-gate 	    kregs[KREG_TRAPNO], (kregs[KREG_FS] & 0xffff), kregs[KREG_FSBASE]);
1390Sstevel@tonic-gate 	mdb_printf("   %%err = 0x%x\t\t%%gs = 0x%04x\tgsbase = 0x%0?p\n",
1400Sstevel@tonic-gate 	    kregs[KREG_ERR], (kregs[KREG_GS] & 0xffff), kregs[KREG_GSBASE]);
1410Sstevel@tonic-gate }
1420Sstevel@tonic-gate 
143*170Ssherrym 
144*170Ssherrym 
145*170Ssherrym /*
146*170Ssherrym  * Sun Studio 10 patch compiler and gcc 3.4.3 Sun branch implemented a
147*170Ssherrym  * "-save_args" option on amd64.  When the option is specified, INTEGER
148*170Ssherrym  * type function arguments passed via registers will be saved on the stack
149*170Ssherrym  * immediately after %rbp, and will not be modified through out the life
150*170Ssherrym  * of the routine.
151*170Ssherrym  *
152*170Ssherrym  *				+--------+
153*170Ssherrym  *		%rbp	-->     |  %rbp  |
154*170Ssherrym  *				+--------+
155*170Ssherrym  *		-0x8(%rbp)	|  %rdi  |
156*170Ssherrym  *				+--------+
157*170Ssherrym  *		-0x10(%rbp)	|  %rsi  |
158*170Ssherrym  *				+--------+
159*170Ssherrym  *		-0x18(%rbp)	|  %rdx  |
160*170Ssherrym  *				+--------+
161*170Ssherrym  *		-0x20(%rbp)	|  %rcx  |
162*170Ssherrym  *				+--------+
163*170Ssherrym  *		-0x28(%rbp)	|  %r8   |
164*170Ssherrym  *				+--------+
165*170Ssherrym  *		-0x30(%rbp)	|  %r9   |
166*170Ssherrym  *				+--------+
167*170Ssherrym  *
168*170Ssherrym  *
169*170Ssherrym  * For example, for the following function,
170*170Ssherrym  *
171*170Ssherrym  * void
172*170Ssherrym  * foo(int a1, int a2, int a3, int a4, int a5, int a6, int a7)
173*170Ssherrym  * {
174*170Ssherrym  * ...
175*170Ssherrym  * }
176*170Ssherrym  *
177*170Ssherrym  * Disassembled code will look something like the following:
178*170Ssherrym  *
179*170Ssherrym  *     pushq	%rbp
180*170Ssherrym  *     movq	%rsp, %rbp
181*170Ssherrym  *     subq	$imm8, %rsp			**
182*170Ssherrym  *     movq	%rdi, -0x8(%rbp)
183*170Ssherrym  *     movq	%rsi, -0x10(%rbp)
184*170Ssherrym  *     movq	%rdx, -0x18(%rbp)
185*170Ssherrym  *     movq	%rcx, -0x20(%rbp)
186*170Ssherrym  *     movq	%r8, -0x28(%rbp)
187*170Ssherrym  *     movq	%r9, -0x30(%rbp)
188*170Ssherrym  *     ...
189*170Ssherrym  * or
190*170Ssherrym  *     pushq	%rbp
191*170Ssherrym  *     movq	%rsp, %rbp
192*170Ssherrym  *     subq	$imm8, %rsp			**
193*170Ssherrym  *     movq	%r9, -0x30(%rbp)
194*170Ssherrym  *     movq	%r8, -0x28(%rbp)
195*170Ssherrym  *     movq	%rcx, -0x20(%rbp)
196*170Ssherrym  *     movq	%rdx, -0x18(%rbp)
197*170Ssherrym  *     movq	%rsi, -0x10(%rbp)
198*170Ssherrym  *     movq	%rdi, -0x8(%rbp)
199*170Ssherrym  *     ...
200*170Ssherrym  *
201*170Ssherrym  * **: The space being reserved is in addition to what the current
202*170Ssherrym  *     function prolog already reserves.
203*170Ssherrym  *
204*170Ssherrym  * If there are odd number of arguments to a function, additional space is
205*170Ssherrym  * reserved on the stack to maintain 16-byte alignment.  For example,
206*170Ssherrym  *
207*170Ssherrym  *     argc == 0: no argument saving.
208*170Ssherrym  *     argc == 3: save 3, but space for 4 is reserved
209*170Ssherrym  *     argc == 7: save 6.
210*170Ssherrym  */
211*170Ssherrym 
212*170Ssherrym /*
213*170Ssherrym  * The longest instruction sequence in bytes before all 6 arguments are
214*170Ssherrym  * saved on the stack.  This value depends on compiler implementation,
215*170Ssherrym  * therefore it should be examined periodically to guarantee accuracy.
216*170Ssherrym  */
217*170Ssherrym #define	SEQ_LEN		80
218*170Ssherrym 
219*170Ssherrym /*
220*170Ssherrym  * Size of the instruction sequence arrays.  It should correspond to
221*170Ssherrym  * the maximum number of arguments passed via registers.
222*170Ssherrym  */
223*170Ssherrym #define	INSTR_ARRAY_SIZE	6
224*170Ssherrym 
225*170Ssherrym #define	INSTR4(ins, off)	\
226*170Ssherrym 	(ins[(off)] + (ins[(off) + 1] << 8) + (ins[(off + 2)] << 16) + \
227*170Ssherrym 	(ins[(off) + 3] << 24))
228*170Ssherrym 
229*170Ssherrym /*
230*170Ssherrym  * Sun Studio 10 patch implementation saves %rdi first;
231*170Ssherrym  * GCC 3.4.3 Sun branch implementation saves them in reverse order.
232*170Ssherrym  */
233*170Ssherrym static const uint32_t save_instr[INSTR_ARRAY_SIZE] = {
234*170Ssherrym 	0xf87d8948,	/* movq %rdi, -0x8(%rbp) */
235*170Ssherrym 	0xf0758948,	/* movq %rsi, -0x10(%rbp) */
236*170Ssherrym 	0xe8558948,	/* movq %rdx, -0x18(%rbp) */
237*170Ssherrym 	0xe04d8948,	/* movq %rcx, -0x20(%rbp) */
238*170Ssherrym 	0xd845894c,	/* movq %r8, -0x28(%rbp) */
239*170Ssherrym 	0xd04d894c	/* movq %r9, -0x30(%rbp) */
240*170Ssherrym };
241*170Ssherrym 
242*170Ssherrym static const uint32_t save_fp_instr[2] = {
243*170Ssherrym 	0xe5894855,	/* pushq %rbp; movq %rsp,%rbp, encoding 1 */
244*170Ssherrym 	0xec8b4855	/* pushq %rbp; movq %rsp,%rbp, encoding 2 */
245*170Ssherrym };
246*170Ssherrym 
247*170Ssherrym /*
248*170Ssherrym  * Look for the above instruction sequences as indicators for register
249*170Ssherrym  * arguments being available on the stack.
250*170Ssherrym  */
251*170Ssherrym static int
252*170Ssherrym is_argsaved(mdb_tgt_t *t, uintptr_t fstart, uint64_t size, uint_t argc,
253*170Ssherrym     int start_index)
254*170Ssherrym {
255*170Ssherrym 	uint8_t		ins[SEQ_LEN];
256*170Ssherrym 	int		i, j;
257*170Ssherrym 	uint32_t	n;
258*170Ssherrym 
259*170Ssherrym 	size = MIN(size, SEQ_LEN);
260*170Ssherrym 	argc = MIN((start_index + argc), INSTR_ARRAY_SIZE);
261*170Ssherrym 
262*170Ssherrym 	if (mdb_tgt_vread(t, ins, size, fstart) != size)
263*170Ssherrym 		return (0);
264*170Ssherrym 
265*170Ssherrym 	/*
266*170Ssherrym 	 * Make sure framepointer has been saved.
267*170Ssherrym 	 */
268*170Ssherrym 	n = INSTR4(ins, 0);
269*170Ssherrym 	for (i = 0; i < 2; i++) {
270*170Ssherrym 		if (n == save_fp_instr[i])
271*170Ssherrym 			break;
272*170Ssherrym 	}
273*170Ssherrym 
274*170Ssherrym 	if (i >= 2)
275*170Ssherrym 		return (0);
276*170Ssherrym 
277*170Ssherrym 	/*
278*170Ssherrym 	 * Compare against Sun Studio implementation
279*170Ssherrym 	 */
280*170Ssherrym 	for (i = 8, j = start_index; i < size - 4; i++) {
281*170Ssherrym 		n = INSTR4(ins, i);
282*170Ssherrym 
283*170Ssherrym 		if (n == save_instr[j]) {
284*170Ssherrym 			i += 3;
285*170Ssherrym 			if (++j >= argc)
286*170Ssherrym 				return (1);
287*170Ssherrym 		}
288*170Ssherrym 	}
289*170Ssherrym 
290*170Ssherrym 	/*
291*170Ssherrym 	 * Compare against GCC implementation
292*170Ssherrym 	 */
293*170Ssherrym 	for (i = 8, j = argc - 1; i < size - 4; i++) {
294*170Ssherrym 		n = INSTR4(ins, i);
295*170Ssherrym 
296*170Ssherrym 		if (n == save_instr[j]) {
297*170Ssherrym 			i += 3;
298*170Ssherrym 			if (--j < start_index)
299*170Ssherrym 				return (1);
300*170Ssherrym 		}
301*170Ssherrym 	}
302*170Ssherrym 
303*170Ssherrym 	return (0);
304*170Ssherrym }
305*170Ssherrym 
3060Sstevel@tonic-gate int
3070Sstevel@tonic-gate mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
3080Sstevel@tonic-gate     mdb_tgt_stack_f *func, void *arg)
3090Sstevel@tonic-gate {
3100Sstevel@tonic-gate 	mdb_tgt_gregset_t gregs;
3110Sstevel@tonic-gate 	kreg_t *kregs = &gregs.kregs[0];
3120Sstevel@tonic-gate 	int got_pc = (gsp->kregs[KREG_RIP] != 0);
313*170Ssherrym 	uint_t argc, reg_argc;
314*170Ssherrym 	long fr_argv[32];
315*170Ssherrym 	int start_index; /* index to save_instr where to start comparison */
316*170Ssherrym 	int i;
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	struct {
3190Sstevel@tonic-gate 		uintptr_t fr_savfp;
3200Sstevel@tonic-gate 		uintptr_t fr_savpc;
3210Sstevel@tonic-gate 	} fr;
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	uintptr_t fp = gsp->kregs[KREG_RBP];
3240Sstevel@tonic-gate 	uintptr_t pc = gsp->kregs[KREG_RIP];
325*170Ssherrym 	uintptr_t curpc;
326*170Ssherrym 
327*170Ssherrym 	ssize_t size;
328*170Ssherrym 
329*170Ssherrym 	GElf_Sym s;
330*170Ssherrym 	mdb_syminfo_t sip;
331*170Ssherrym 	mdb_ctf_funcinfo_t mfp;
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	bcopy(gsp, &gregs, sizeof (gregs));
3340Sstevel@tonic-gate 
3350Sstevel@tonic-gate 	while (fp != 0) {
3360Sstevel@tonic-gate 
337*170Ssherrym 		curpc = pc;
338*170Ssherrym 
3390Sstevel@tonic-gate 		if (fp & (STACK_ALIGN - 1))
3400Sstevel@tonic-gate 			return (set_errno(EMDB_STKALIGN));
3410Sstevel@tonic-gate 
342*170Ssherrym 		if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) != sizeof (fr))
343*170Ssherrym 			return (-1);	/* errno has been set for us */
344*170Ssherrym 
345*170Ssherrym 		if ((mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY,
346*170Ssherrym 		    NULL, 0, &s, &sip) == 0) &&
347*170Ssherrym 		    (mdb_ctf_func_info(&s, &sip, &mfp) == 0)) {
348*170Ssherrym 			int return_type = mdb_ctf_type_kind(mfp.mtf_return);
349*170Ssherrym 			argc = mfp.mtf_argc;
350*170Ssherrym 			/*
351*170Ssherrym 			 * If the function returns a structure or union,
352*170Ssherrym 			 * %rdi contains the address in which to store the
353*170Ssherrym 			 * return value rather than for an argument.
354*170Ssherrym 			 */
355*170Ssherrym 			if (return_type == CTF_K_STRUCT ||
356*170Ssherrym 			    return_type == CTF_K_UNION)
357*170Ssherrym 				start_index = 1;
358*170Ssherrym 			else
359*170Ssherrym 				start_index = 0;
360*170Ssherrym 		} else {
361*170Ssherrym 			argc = 0;
362*170Ssherrym 		}
363*170Ssherrym 
364*170Ssherrym 		if (argc != 0 && is_argsaved(t, s.st_value, s.st_size,
365*170Ssherrym 		    argc, start_index)) {
3660Sstevel@tonic-gate 
367*170Ssherrym 			/* Upto to 6 arguments are passed via registers */
368*170Ssherrym 			reg_argc = MIN(6, mfp.mtf_argc);
369*170Ssherrym 			size = reg_argc * sizeof (long);
370*170Ssherrym 
371*170Ssherrym 			if (mdb_tgt_vread(t, fr_argv, size, (fp - size))
372*170Ssherrym 			    != size)
373*170Ssherrym 				return (-1);	/* errno has been set for us */
374*170Ssherrym 
375*170Ssherrym 			/*
376*170Ssherrym 			 * Arrange the arguments in the right order for
377*170Ssherrym 			 * printing.
378*170Ssherrym 			 */
379*170Ssherrym 			for (i = 0; i < (reg_argc >> 1); i++) {
380*170Ssherrym 				long t = fr_argv[i];
381*170Ssherrym 
382*170Ssherrym 				fr_argv[i] = fr_argv[reg_argc - i - 1];
383*170Ssherrym 				fr_argv[reg_argc - i - 1] = t;
384*170Ssherrym 			}
385*170Ssherrym 
386*170Ssherrym 			if (argc > 6) {
387*170Ssherrym 				size = (argc - 6) * sizeof (long);
388*170Ssherrym 				if (mdb_tgt_vread(t, &fr_argv[6], size,
389*170Ssherrym 				    fp + sizeof (fr)) != size)
390*170Ssherrym 					return (-1); /* errno has been set */
391*170Ssherrym 			}
392*170Ssherrym 		} else
393*170Ssherrym 			argc = 0;
394*170Ssherrym 
395*170Ssherrym 		if (got_pc && func(arg, pc, argc, fr_argv, &gregs) != 0)
3960Sstevel@tonic-gate 			break;
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 		kregs[KREG_RSP] = kregs[KREG_RBP];
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate 		kregs[KREG_RBP] = fp = fr.fr_savfp;
4010Sstevel@tonic-gate 		kregs[KREG_RIP] = pc = fr.fr_savpc;
4020Sstevel@tonic-gate 
403*170Ssherrym 		if (curpc == pc)
404*170Ssherrym 			break;
405*170Ssherrym 
4060Sstevel@tonic-gate 		got_pc = (pc != 0);
4070Sstevel@tonic-gate 	}
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	return (0);
4100Sstevel@tonic-gate }
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate /*
4130Sstevel@tonic-gate  * Determine the return address for the current frame.  Typically this is the
4140Sstevel@tonic-gate  * fr_savpc value from the current frame, but we also perform some special
4150Sstevel@tonic-gate  * handling to see if we are stopped on one of the first two instructions of
4160Sstevel@tonic-gate  * a typical function prologue, in which case %rbp will not be set up yet.
4170Sstevel@tonic-gate  */
4180Sstevel@tonic-gate int
4190Sstevel@tonic-gate mdb_amd64_step_out(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, kreg_t fp, kreg_t sp,
4200Sstevel@tonic-gate     mdb_instr_t curinstr)
4210Sstevel@tonic-gate {
4220Sstevel@tonic-gate 	struct frame fr;
4230Sstevel@tonic-gate 	GElf_Sym s;
4240Sstevel@tonic-gate 	char buf[1];
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	enum {
4270Sstevel@tonic-gate 		M_PUSHQ_RBP	= 0x55,	/* pushq %rbp */
4280Sstevel@tonic-gate 		M_REX_W		= 0x48, /* REX prefix with only W set */
4290Sstevel@tonic-gate 		M_MOVL_RBP	= 0x8b	/* movq %rsp, %rbp with prefix */
4300Sstevel@tonic-gate 	};
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	if (mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY,
4330Sstevel@tonic-gate 	    buf, 0, &s, NULL) == 0) {
4340Sstevel@tonic-gate 		if (pc == s.st_value && curinstr == M_PUSHQ_RBP)
4350Sstevel@tonic-gate 			fp = sp - 8;
4360Sstevel@tonic-gate 		else if (pc == s.st_value + 1 && curinstr == M_REX_W) {
4370Sstevel@tonic-gate 			if (mdb_tgt_vread(t, &curinstr, sizeof (curinstr),
4380Sstevel@tonic-gate 			    pc + 1) == sizeof (curinstr) && curinstr ==
4390Sstevel@tonic-gate 			    M_MOVL_RBP)
4400Sstevel@tonic-gate 				fp = sp;
4410Sstevel@tonic-gate 		}
4420Sstevel@tonic-gate 	}
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) == sizeof (fr)) {
4450Sstevel@tonic-gate 		*p = fr.fr_savpc;
4460Sstevel@tonic-gate 		return (0);
4470Sstevel@tonic-gate 	}
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	return (-1); /* errno is set for us */
4500Sstevel@tonic-gate }
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate /*ARGSUSED*/
4530Sstevel@tonic-gate int
4540Sstevel@tonic-gate mdb_amd64_next(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, mdb_instr_t curinstr)
4550Sstevel@tonic-gate {
4560Sstevel@tonic-gate 	mdb_tgt_addr_t npc;
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	enum {
4590Sstevel@tonic-gate 		M_CALL_REL = 0xe8, /* call near with relative displacement */
4600Sstevel@tonic-gate 		M_CALL_REG = 0xff, /* call near indirect or call far register */
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 		M_REX_LO = 0x40,
4630Sstevel@tonic-gate 		M_REX_HI = 0x4f
4640Sstevel@tonic-gate 	};
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	/*
4670Sstevel@tonic-gate 	 * If the opcode is a near call with relative displacement, assume the
4680Sstevel@tonic-gate 	 * displacement is a rel32 from the next instruction.
4690Sstevel@tonic-gate 	 */
4700Sstevel@tonic-gate 	if (curinstr == M_CALL_REL) {
4710Sstevel@tonic-gate 		*p = pc + sizeof (mdb_instr_t) + sizeof (uint32_t);
4720Sstevel@tonic-gate 		return (0);
4730Sstevel@tonic-gate 	}
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	/* Skip the rex prefix, if any */
4760Sstevel@tonic-gate 	if (curinstr >= M_REX_LO && curinstr <= M_REX_HI &&
4770Sstevel@tonic-gate 	    mdb_tgt_vread(t, &curinstr, sizeof (curinstr), pc) !=
4780Sstevel@tonic-gate 	    sizeof (curinstr))
4790Sstevel@tonic-gate 		return (-1); /* errno is set for us */
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	if (curinstr != M_CALL_REG) {
4820Sstevel@tonic-gate 		/* It's not a call */
4830Sstevel@tonic-gate 		return (set_errno(EAGAIN));
4840Sstevel@tonic-gate 	}
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	if ((npc = mdb_dis_nextins(mdb.m_disasm, t, MDB_TGT_AS_VIRT, pc)) == pc)
4870Sstevel@tonic-gate 		return (-1); /* errno is set for us */
4880Sstevel@tonic-gate 
4890Sstevel@tonic-gate 	*p = npc;
4900Sstevel@tonic-gate 	return (0);
4910Sstevel@tonic-gate }
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate /*ARGSUSED*/
4940Sstevel@tonic-gate int
4950Sstevel@tonic-gate mdb_amd64_kvm_frame(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
4960Sstevel@tonic-gate     const mdb_tgt_gregset_t *gregs)
4970Sstevel@tonic-gate {
4980Sstevel@tonic-gate 	argc = MIN(argc, (uintptr_t)arglim);
4990Sstevel@tonic-gate 	mdb_printf("%a(", pc);
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	if (argc != 0) {
5020Sstevel@tonic-gate 		mdb_printf("%lr", *argv++);
5030Sstevel@tonic-gate 		for (argc--; argc != 0; argc--)
5040Sstevel@tonic-gate 			mdb_printf(", %lr", *argv++);
5050Sstevel@tonic-gate 	}
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate 	mdb_printf(")\n");
5080Sstevel@tonic-gate 	return (0);
5090Sstevel@tonic-gate }
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate int
5120Sstevel@tonic-gate mdb_amd64_kvm_framev(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
5130Sstevel@tonic-gate     const mdb_tgt_gregset_t *gregs)
5140Sstevel@tonic-gate {
515*170Ssherrym 	/*
516*170Ssherrym 	 * Historically adb limited stack trace argument display to a fixed-
517*170Ssherrym 	 * size number of arguments since no symbolic debugging info existed.
518*170Ssherrym 	 * On amd64 we can detect the true number of saved arguments so only
519*170Ssherrym 	 * respect an arglim of zero; otherwise display the entire argv[].
520*170Ssherrym 	 */
521*170Ssherrym 	if (arglim == 0)
522*170Ssherrym 		argc = 0;
523*170Ssherrym 
5240Sstevel@tonic-gate 	mdb_printf("%0?lr %a(", gregs->kregs[KREG_RBP], pc);
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 	if (argc != 0) {
5270Sstevel@tonic-gate 		mdb_printf("%lr", *argv++);
5280Sstevel@tonic-gate 		for (argc--; argc != 0; argc--)
5290Sstevel@tonic-gate 			mdb_printf(", %lr", *argv++);
5300Sstevel@tonic-gate 	}
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 	mdb_printf(")\n");
5330Sstevel@tonic-gate 	return (0);
5340Sstevel@tonic-gate }
535