xref: /illumos-gate/usr/src/cmd/mdb/intel/mdb/mdb_amd64util.c (revision 5f633405e54baecc905f42c59f8fc7aaca7a7c05)
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  * Copyright (c) 2018, Joyent, Inc.  All rights reserved.
28  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
29  * Copyright (c) 2013 by Delphix. All rights reserved.
30  */
31 
32 #include <sys/types.h>
33 #include <sys/reg.h>
34 #include <sys/privregs.h>
35 #include <sys/stack.h>
36 #include <sys/frame.h>
37 
38 #include <mdb/mdb_target_impl.h>
39 #include <mdb/mdb_kreg_impl.h>
40 #include <mdb/mdb_debug.h>
41 #include <mdb/mdb_modapi.h>
42 #include <mdb/mdb_amd64util.h>
43 #include <mdb/mdb_ctf.h>
44 #include <mdb/mdb_err.h>
45 #include <mdb/mdb.h>
46 
47 #include <saveargs.h>
48 
49 /*
50  * This array is used by the getareg and putareg entry points, and also by our
51  * register variable discipline.
52  */
53 
54 const mdb_tgt_regdesc_t mdb_amd64_kregs[] = {
55 	{ "savfp", KREG_SAVFP, MDB_TGT_R_EXPORT },
56 	{ "savpc", KREG_SAVPC, MDB_TGT_R_EXPORT },
57 	{ "rdi", KREG_RDI, MDB_TGT_R_EXPORT },
58 	{ "edi", KREG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
59 	{ "di",  KREG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
60 	{ "dil", KREG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
61 	{ "rsi", KREG_RSI, MDB_TGT_R_EXPORT },
62 	{ "esi", KREG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
63 	{ "si",  KREG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
64 	{ "sil", KREG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
65 	{ "rdx", KREG_RDX, MDB_TGT_R_EXPORT },
66 	{ "edx", KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
67 	{ "dx",  KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
68 	{ "dh",  KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
69 	{ "dl",  KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
70 	{ "rcx", KREG_RCX, MDB_TGT_R_EXPORT },
71 	{ "ecx", KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
72 	{ "cx",  KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
73 	{ "ch",  KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
74 	{ "cl",  KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
75 	{ "r8", KREG_R8, MDB_TGT_R_EXPORT },
76 	{ "r8d", KREG_R8,  MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
77 	{ "r8w", KREG_R8,  MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
78 	{ "r8l", KREG_R8,  MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
79 	{ "r9", KREG_R9, MDB_TGT_R_EXPORT },
80 	{ "r9d", KREG_R8,  MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
81 	{ "r9w", KREG_R8,  MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
82 	{ "r9l", KREG_R8,  MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
83 	{ "rax", KREG_RAX, MDB_TGT_R_EXPORT },
84 	{ "eax", KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
85 	{ "ax",  KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
86 	{ "ah",  KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
87 	{ "al",  KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
88 	{ "rbx", KREG_RBX, MDB_TGT_R_EXPORT },
89 	{ "ebx", KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
90 	{ "bx",  KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
91 	{ "bh",  KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
92 	{ "bl",  KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
93 	{ "rbp", KREG_RBP, MDB_TGT_R_EXPORT },
94 	{ "ebp", KREG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
95 	{ "bp",  KREG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
96 	{ "bpl", KREG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
97 	{ "r10", KREG_R10, MDB_TGT_R_EXPORT },
98 	{ "r10d", KREG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
99 	{ "r10w", KREG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
100 	{ "r10l", KREG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
101 	{ "r11", KREG_R11, MDB_TGT_R_EXPORT },
102 	{ "r11d", KREG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
103 	{ "r11w", KREG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
104 	{ "r11l", KREG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
105 	{ "r12", KREG_R12, MDB_TGT_R_EXPORT },
106 	{ "r12d", KREG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
107 	{ "r12w", KREG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
108 	{ "r12l", KREG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
109 	{ "r13", KREG_R13, MDB_TGT_R_EXPORT },
110 	{ "r13d", KREG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
111 	{ "r13w", KREG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
112 	{ "r13l", KREG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
113 	{ "r14", KREG_R14, MDB_TGT_R_EXPORT },
114 	{ "r14d", KREG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
115 	{ "r14w", KREG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
116 	{ "r14l", KREG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
117 	{ "r15", KREG_R15, MDB_TGT_R_EXPORT },
118 	{ "r15d", KREG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
119 	{ "r15w", KREG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
120 	{ "r15l", KREG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
121 	{ "ds", KREG_DS, MDB_TGT_R_EXPORT },
122 	{ "es", KREG_ES, MDB_TGT_R_EXPORT },
123 	{ "fs", KREG_FS, MDB_TGT_R_EXPORT },
124 	{ "gs", KREG_GS, MDB_TGT_R_EXPORT },
125 	{ "trapno", KREG_TRAPNO, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
126 	{ "err", KREG_ERR, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
127 	{ "rip", KREG_RIP, MDB_TGT_R_EXPORT },
128 	{ "cs", KREG_CS, MDB_TGT_R_EXPORT },
129 	{ "rflags", KREG_RFLAGS, MDB_TGT_R_EXPORT },
130 	{ "eflags", KREG_RFLAGS, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
131 	{ "rsp", KREG_RSP, MDB_TGT_R_EXPORT },
132 	{ "esp", KREG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
133 	{ "sp",  KREG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
134 	{ "spl", KREG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
135 	{ "ss", KREG_SS, MDB_TGT_R_EXPORT },
136 	{ "gsbase", KREG_GSBASE, MDB_TGT_R_EXPORT },
137 	{ "kgsbase", KREG_KGSBASE, MDB_TGT_R_EXPORT },
138 	{ "cr2", KREG_CR2, MDB_TGT_R_EXPORT },
139 	{ "cr3", KREG_CR3, MDB_TGT_R_EXPORT },
140 	{ NULL, 0, 0 }
141 };
142 
143 void
144 mdb_amd64_printregs(const mdb_tgt_gregset_t *gregs)
145 {
146 	const kreg_t *kregs = &gregs->kregs[0];
147 	kreg_t rflags = kregs[KREG_RFLAGS];
148 
149 #define	GETREG2(x) ((uintptr_t)kregs[(x)]), ((uintptr_t)kregs[(x)])
150 
151 	mdb_printf("%%rax = 0x%0?p %15A %%r9  = 0x%0?p %A\n",
152 	    GETREG2(KREG_RAX), GETREG2(KREG_R9));
153 	mdb_printf("%%rbx = 0x%0?p %15A %%r10 = 0x%0?p %A\n",
154 	    GETREG2(KREG_RBX), GETREG2(KREG_R10));
155 	mdb_printf("%%rcx = 0x%0?p %15A %%r11 = 0x%0?p %A\n",
156 	    GETREG2(KREG_RCX), GETREG2(KREG_R11));
157 	mdb_printf("%%rdx = 0x%0?p %15A %%r12 = 0x%0?p %A\n",
158 	    GETREG2(KREG_RDX), GETREG2(KREG_R12));
159 	mdb_printf("%%rsi = 0x%0?p %15A %%r13 = 0x%0?p %A\n",
160 	    GETREG2(KREG_RSI), GETREG2(KREG_R13));
161 	mdb_printf("%%rdi = 0x%0?p %15A %%r14 = 0x%0?p %A\n",
162 	    GETREG2(KREG_RDI), GETREG2(KREG_R14));
163 	mdb_printf("%%r8  = 0x%0?p %15A %%r15 = 0x%0?p %A\n\n",
164 	    GETREG2(KREG_R8), GETREG2(KREG_R15));
165 
166 	mdb_printf("%%rip = 0x%0?p %A\n", GETREG2(KREG_RIP));
167 	mdb_printf("%%rbp = 0x%0?p\n", kregs[KREG_RBP]);
168 	mdb_printf("%%rsp = 0x%0?p\n", kregs[KREG_RSP]);
169 
170 	mdb_printf("%%rflags = 0x%08x\n", rflags);
171 
172 	mdb_printf("  id=%u vip=%u vif=%u ac=%u vm=%u rf=%u nt=%u iopl=0x%x\n",
173 	    (rflags & KREG_EFLAGS_ID_MASK) >> KREG_EFLAGS_ID_SHIFT,
174 	    (rflags & KREG_EFLAGS_VIP_MASK) >> KREG_EFLAGS_VIP_SHIFT,
175 	    (rflags & KREG_EFLAGS_VIF_MASK) >> KREG_EFLAGS_VIF_SHIFT,
176 	    (rflags & KREG_EFLAGS_AC_MASK) >> KREG_EFLAGS_AC_SHIFT,
177 	    (rflags & KREG_EFLAGS_VM_MASK) >> KREG_EFLAGS_VM_SHIFT,
178 	    (rflags & KREG_EFLAGS_RF_MASK) >> KREG_EFLAGS_RF_SHIFT,
179 	    (rflags & KREG_EFLAGS_NT_MASK) >> KREG_EFLAGS_NT_SHIFT,
180 	    (rflags & KREG_EFLAGS_IOPL_MASK) >> KREG_EFLAGS_IOPL_SHIFT);
181 
182 	mdb_printf("  status=<%s,%s,%s,%s,%s,%s,%s,%s,%s>\n\n",
183 	    (rflags & KREG_EFLAGS_OF_MASK) ? "OF" : "of",
184 	    (rflags & KREG_EFLAGS_DF_MASK) ? "DF" : "df",
185 	    (rflags & KREG_EFLAGS_IF_MASK) ? "IF" : "if",
186 	    (rflags & KREG_EFLAGS_TF_MASK) ? "TF" : "tf",
187 	    (rflags & KREG_EFLAGS_SF_MASK) ? "SF" : "sf",
188 	    (rflags & KREG_EFLAGS_ZF_MASK) ? "ZF" : "zf",
189 	    (rflags & KREG_EFLAGS_AF_MASK) ? "AF" : "af",
190 	    (rflags & KREG_EFLAGS_PF_MASK) ? "PF" : "pf",
191 	    (rflags & KREG_EFLAGS_CF_MASK) ? "CF" : "cf");
192 
193 	mdb_printf("%%cs = 0x%04x\t%%ds = 0x%04x\t"
194 	    "%%es = 0x%04x\t%%fs = 0x%04x\n", kregs[KREG_CS], kregs[KREG_DS],
195 	    kregs[KREG_ES], kregs[KREG_FS] & 0xffff);
196 	mdb_printf("%%gs = 0x%04x\t%%gsbase = 0x%lx\t%%kgsbase = 0x%lx\n",
197 	    kregs[KREG_GS] & 0xffff, kregs[KREG_GSBASE], kregs[KREG_KGSBASE]);
198 	mdb_printf("%%trapno = 0x%x\t%%err = 0x%x\t%%cr2 = 0x%lx\t"
199 	    "%%cr3 = 0x%lx\n", kregs[KREG_TRAPNO], kregs[KREG_ERR],
200 	    kregs[KREG_CR2], kregs[KREG_CR3]);
201 }
202 
203 int
204 mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
205     mdb_tgt_stack_f *func, void *arg)
206 {
207 	mdb_tgt_gregset_t gregs;
208 	kreg_t *kregs = &gregs.kregs[0];
209 	int got_pc = (gsp->kregs[KREG_RIP] != 0);
210 	uint_t argc, reg_argc;
211 	long fr_argv[32];
212 	int start_index; /* index to save_instr where to start comparison */
213 	int err;
214 	int i;
215 
216 	struct fr {
217 		uintptr_t fr_savfp;
218 		uintptr_t fr_savpc;
219 	} fr;
220 
221 	uintptr_t fp = gsp->kregs[KREG_RBP];
222 	uintptr_t pc = gsp->kregs[KREG_RIP];
223 	uintptr_t lastfp = 0;
224 
225 	ssize_t size;
226 	ssize_t insnsize;
227 	uint8_t ins[SAVEARGS_INSN_SEQ_LEN];
228 
229 	GElf_Sym s;
230 	mdb_syminfo_t sip;
231 	mdb_ctf_funcinfo_t mfp;
232 	int xpv_panic = 0;
233 	int advance_tortoise = 1;
234 	uintptr_t tortoise_fp = 0;
235 #ifndef	_KMDB
236 	int xp;
237 
238 	if ((mdb_readsym(&xp, sizeof (xp), "xpv_panicking") != -1) && (xp > 0))
239 		xpv_panic = 1;
240 #endif
241 
242 	bcopy(gsp, &gregs, sizeof (gregs));
243 
244 	while (fp != 0) {
245 		int args_style = 0;
246 
247 		if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) != sizeof (fr)) {
248 			err = EMDB_NOMAP;
249 			goto badfp;
250 		}
251 
252 		if (tortoise_fp == 0) {
253 			tortoise_fp = fp;
254 		} else {
255 			/*
256 			 * Advance tortoise_fp every other frame, so we detect
257 			 * cycles with Floyd's tortoise/hare.
258 			 */
259 			if (advance_tortoise != 0) {
260 				struct fr tfr;
261 
262 				if (mdb_tgt_vread(t, &tfr, sizeof (tfr),
263 				    tortoise_fp) != sizeof (tfr)) {
264 					err = EMDB_NOMAP;
265 					goto badfp;
266 				}
267 
268 				tortoise_fp = tfr.fr_savfp;
269 			}
270 
271 			if (fp == tortoise_fp) {
272 				err = EMDB_STKFRAME;
273 				goto badfp;
274 			}
275 		}
276 
277 		advance_tortoise = !advance_tortoise;
278 
279 		if ((mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY,
280 		    NULL, 0, &s, &sip) == 0) &&
281 		    (mdb_ctf_func_info(&s, &sip, &mfp) == 0)) {
282 			int return_type = mdb_ctf_type_kind(mfp.mtf_return);
283 			mdb_ctf_id_t args_types[5];
284 
285 			argc = mfp.mtf_argc;
286 
287 			/*
288 			 * If the function returns a structure or union
289 			 * greater than 16 bytes in size %rdi contains the
290 			 * address in which to store the return value rather
291 			 * than for an argument.
292 			 */
293 			if ((return_type == CTF_K_STRUCT ||
294 			    return_type == CTF_K_UNION) &&
295 			    mdb_ctf_type_size(mfp.mtf_return) > 16)
296 				start_index = 1;
297 			else
298 				start_index = 0;
299 
300 			/*
301 			 * If any of the first 5 arguments are a structure
302 			 * less than 16 bytes in size, it will be passed
303 			 * spread across two argument registers, and we will
304 			 * not cope.
305 			 */
306 			if (mdb_ctf_func_args(&mfp, 5, args_types) == CTF_ERR)
307 				argc = 0;
308 
309 			for (i = 0; i < MIN(5, argc); i++) {
310 				int t = mdb_ctf_type_kind(args_types[i]);
311 
312 				if (((t == CTF_K_STRUCT) ||
313 				    (t == CTF_K_UNION)) &&
314 				    mdb_ctf_type_size(args_types[i]) <= 16) {
315 					argc = 0;
316 					break;
317 				}
318 			}
319 		} else {
320 			argc = 0;
321 		}
322 
323 		/*
324 		 * The number of instructions to search for argument saving is
325 		 * limited such that only instructions prior to %pc are
326 		 * considered such that we never read arguments from a
327 		 * function where the saving code has not in fact yet
328 		 * executed.
329 		 */
330 		insnsize = MIN(MIN(s.st_size, SAVEARGS_INSN_SEQ_LEN),
331 		    pc - s.st_value);
332 
333 		if (mdb_tgt_vread(t, ins, insnsize, s.st_value) != insnsize)
334 			argc = 0;
335 
336 		if ((argc != 0) &&
337 		    ((args_style = saveargs_has_args(ins, insnsize, argc,
338 		    start_index)) != SAVEARGS_NO_ARGS)) {
339 			/* Up to 6 arguments are passed via registers */
340 			reg_argc = MIN((6 - start_index), mfp.mtf_argc);
341 			size = reg_argc * sizeof (long);
342 
343 			/*
344 			 * If Studio pushed a structure return address as an
345 			 * argument, we need to read one more argument than
346 			 * actually exists (the addr) to make everything line
347 			 * up.
348 			 */
349 			if (args_style == SAVEARGS_STRUCT_ARGS)
350 				size += sizeof (long);
351 
352 			if (mdb_tgt_vread(t, fr_argv, size, (fp - size))
353 			    != size)
354 				return (-1);	/* errno has been set for us */
355 
356 			/*
357 			 * Arrange the arguments in the right order for
358 			 * printing.
359 			 */
360 			for (i = 0; i < (reg_argc / 2); i++) {
361 				long t = fr_argv[i];
362 
363 				fr_argv[i] = fr_argv[reg_argc - i - 1];
364 				fr_argv[reg_argc - i - 1] = t;
365 			}
366 
367 			if (argc > reg_argc) {
368 				size = MIN((argc - reg_argc) * sizeof (long),
369 				    sizeof (fr_argv) -
370 				    (reg_argc * sizeof (long)));
371 
372 				if (mdb_tgt_vread(t, &fr_argv[reg_argc], size,
373 				    fp + sizeof (fr)) != size)
374 					return (-1); /* errno has been set */
375 			}
376 		} else {
377 			argc = 0;
378 		}
379 
380 		if (got_pc && func(arg, pc, argc, fr_argv, &gregs) != 0)
381 			break;
382 
383 		kregs[KREG_RSP] = kregs[KREG_RBP];
384 
385 		lastfp = fp;
386 		fp = fr.fr_savfp;
387 		/*
388 		 * The Xen hypervisor marks a stack frame as belonging to
389 		 * an exception by inverting the bits of the pointer to
390 		 * that frame.  We attempt to identify these frames by
391 		 * inverting the pointer and seeing if it is within 0xfff
392 		 * bytes of the last frame.
393 		 */
394 		if (xpv_panic)
395 			if ((fp != 0) && (fp < lastfp) &&
396 			    ((lastfp ^ ~fp) < 0xfff))
397 				fp = ~fp;
398 
399 		kregs[KREG_RBP] = fp;
400 		kregs[KREG_RIP] = pc = fr.fr_savpc;
401 
402 		got_pc = (pc != 0);
403 	}
404 
405 	return (0);
406 
407 badfp:
408 	mdb_printf("%p [%s]", fp, mdb_strerror(err));
409 	return (set_errno(err));
410 }
411 
412 /*
413  * Determine the return address for the current frame.  Typically this is the
414  * fr_savpc value from the current frame, but we also perform some special
415  * handling to see if we are stopped on one of the first two instructions of
416  * a typical function prologue, in which case %rbp will not be set up yet.
417  */
418 int
419 mdb_amd64_step_out(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, kreg_t fp, kreg_t sp,
420     mdb_instr_t curinstr)
421 {
422 	struct frame fr;
423 	GElf_Sym s;
424 	char buf[1];
425 
426 	enum {
427 		M_PUSHQ_RBP	= 0x55,	/* pushq %rbp */
428 		M_REX_W		= 0x48, /* REX prefix with only W set */
429 		M_MOVL_RBP	= 0x8b	/* movq %rsp, %rbp with prefix */
430 	};
431 
432 	if (mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY,
433 	    buf, 0, &s, NULL) == 0) {
434 		if (pc == s.st_value && curinstr == M_PUSHQ_RBP)
435 			fp = sp - 8;
436 		else if (pc == s.st_value + 1 && curinstr == M_REX_W) {
437 			if (mdb_tgt_vread(t, &curinstr, sizeof (curinstr),
438 			    pc + 1) == sizeof (curinstr) && curinstr ==
439 			    M_MOVL_RBP)
440 				fp = sp;
441 		}
442 	}
443 
444 	if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) == sizeof (fr)) {
445 		*p = fr.fr_savpc;
446 		return (0);
447 	}
448 
449 	return (-1); /* errno is set for us */
450 }
451 
452 /*ARGSUSED*/
453 int
454 mdb_amd64_next(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, mdb_instr_t curinstr)
455 {
456 	mdb_tgt_addr_t npc;
457 	mdb_tgt_addr_t callpc;
458 
459 	enum {
460 		M_CALL_REL = 0xe8, /* call near with relative displacement */
461 		M_CALL_REG = 0xff, /* call near indirect or call far register */
462 
463 		M_REX_LO = 0x40,
464 		M_REX_HI = 0x4f
465 	};
466 
467 	/*
468 	 * If the opcode is a near call with relative displacement, assume the
469 	 * displacement is a rel32 from the next instruction.
470 	 */
471 	if (curinstr == M_CALL_REL) {
472 		*p = pc + sizeof (mdb_instr_t) + sizeof (uint32_t);
473 		return (0);
474 	}
475 
476 	/* Skip the rex prefix, if any */
477 	callpc = pc;
478 	while (curinstr >= M_REX_LO && curinstr <= M_REX_HI) {
479 		if (mdb_tgt_vread(t, &curinstr, sizeof (curinstr), ++callpc) !=
480 		    sizeof (curinstr))
481 			return (-1); /* errno is set for us */
482 	}
483 
484 	if (curinstr != M_CALL_REG) {
485 		/* It's not a call */
486 		return (set_errno(EAGAIN));
487 	}
488 
489 	if ((npc = mdb_dis_nextins(mdb.m_disasm, t, MDB_TGT_AS_VIRT, pc)) == pc)
490 		return (-1); /* errno is set for us */
491 
492 	*p = npc;
493 	return (0);
494 }
495 
496 /*ARGSUSED*/
497 int
498 mdb_amd64_kvm_frame(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
499     const mdb_tgt_gregset_t *gregs)
500 {
501 	argc = MIN(argc, (uintptr_t)arglim);
502 	mdb_printf("%a(", pc);
503 
504 	if (argc != 0) {
505 		mdb_printf("%lr", *argv++);
506 		for (argc--; argc != 0; argc--)
507 			mdb_printf(", %lr", *argv++);
508 	}
509 
510 	mdb_printf(")\n");
511 	return (0);
512 }
513 
514 int
515 mdb_amd64_kvm_framev(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
516     const mdb_tgt_gregset_t *gregs)
517 {
518 	/*
519 	 * Historically adb limited stack trace argument display to a fixed-
520 	 * size number of arguments since no symbolic debugging info existed.
521 	 * On amd64 we can detect the true number of saved arguments so only
522 	 * respect an arglim of zero; otherwise display the entire argv[].
523 	 */
524 	if (arglim == 0)
525 		argc = 0;
526 
527 	mdb_printf("%0?lr %a(", gregs->kregs[KREG_RBP], pc);
528 
529 	if (argc != 0) {
530 		mdb_printf("%lr", *argv++);
531 		for (argc--; argc != 0; argc--)
532 			mdb_printf(", %lr", *argv++);
533 	}
534 
535 	mdb_printf(")\n");
536 	return (0);
537 }
538