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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 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 /*
30  * User Process Target Intel 32-bit component
31  *
32  * This file provides the ISA-dependent portion of the user process target.
33  * For more details on the implementation refer to mdb_proc.c.
34  */
35 
36 #include <mdb/mdb_proc.h>
37 #include <mdb/mdb_kreg.h>
38 #include <mdb/mdb_err.h>
39 #include <mdb/mdb_amd64util.h>
40 #include <mdb/mdb.h>
41 
42 #include <sys/frame.h>
43 #include <libproc.h>
44 #include <sys/fp.h>
45 #include <ieeefp.h>
46 
47 const mdb_tgt_regdesc_t pt_regdesc[] = {
48 	{ "r15",	REG_R15,	MDB_TGT_R_EXPORT },
49 	{ "r14",	REG_R14,	MDB_TGT_R_EXPORT },
50 	{ "r13",	REG_R13,	MDB_TGT_R_EXPORT },
51 	{ "r12",	REG_R12,	MDB_TGT_R_EXPORT },
52 	{ "r11",	REG_R11,	MDB_TGT_R_EXPORT },
53 	{ "r10",	REG_R10,	MDB_TGT_R_EXPORT },
54 	{ "r9",		REG_R9,		MDB_TGT_R_EXPORT },
55 	{ "r8",		REG_R8,		MDB_TGT_R_EXPORT },
56 	{ "rdi",	REG_RDI,	MDB_TGT_R_EXPORT },
57 	{ "rsi",	REG_RSI,	MDB_TGT_R_EXPORT },
58 	{ "rbp",	REG_RBP,	MDB_TGT_R_EXPORT },
59 	{ "rbx",	REG_RBX,	MDB_TGT_R_EXPORT },
60 	{ "rdx",	REG_RDX,	MDB_TGT_R_EXPORT },
61 	{ "rcx",	REG_RCX,	MDB_TGT_R_EXPORT },
62 	{ "rax",	REG_RAX,	MDB_TGT_R_EXPORT },
63 	{ "trapno",	REG_TRAPNO,	MDB_TGT_R_EXPORT },
64 	{ "err",	REG_ERR,	MDB_TGT_R_EXPORT },
65 	{ "rip",	REG_RIP,	MDB_TGT_R_EXPORT },
66 	{ "cs",		REG_CS,		MDB_TGT_R_EXPORT },
67 	{ "rflags",	REG_RFL,	MDB_TGT_R_EXPORT },
68 	{ "rsp",	REG_RSP,	MDB_TGT_R_EXPORT },
69 	{ "ss",		REG_SS,		MDB_TGT_R_EXPORT },
70 	{ "fs",		REG_FS,		MDB_TGT_R_EXPORT },
71 	{ "gs",		REG_GS,		MDB_TGT_R_EXPORT },
72 	{ "es",		REG_ES,		MDB_TGT_R_EXPORT },
73 	{ "ds",		REG_DS,		MDB_TGT_R_EXPORT },
74 	{ "fsbase",	REG_FSBASE,	MDB_TGT_R_EXPORT },
75 	{ "gsbase",	REG_GSBASE,	MDB_TGT_R_EXPORT },
76 	{ NULL, 0, 0 }
77 };
78 
79 /*
80  * We cannot rely on pr_instr, because if we hit a breakpoint or the user has
81  * artifically modified memory, it will no longer be correct.
82  */
83 static uint8_t
84 pt_read_instr(mdb_tgt_t *t)
85 {
86 	const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
87 	uint8_t ret = 0;
88 
89 	(void) mdb_tgt_vread(t, &ret, sizeof (ret), psp->pr_reg[REG_RIP]);
90 
91 	return (ret);
92 }
93 
94 /*ARGSUSED*/
95 int
96 pt_regs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
97 {
98 	mdb_tgt_t *t = mdb.m_target;
99 	mdb_tgt_tid_t tid;
100 	prgregset_t grs;
101 	prgreg_t rflags;
102 
103 	if (argc != 0)
104 		return (DCMD_USAGE);
105 
106 	if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_UNDEAD) {
107 		mdb_warn("no process active\n");
108 		return (DCMD_ERR);
109 	}
110 
111 	if (Pstate(t->t_pshandle) == PS_LOST) {
112 		mdb_warn("debugger has lost control of process\n");
113 		return (DCMD_ERR);
114 	}
115 
116 	if (flags & DCMD_ADDRSPEC)
117 		tid = (mdb_tgt_tid_t)addr;
118 	else
119 		tid = PTL_TID(t);
120 
121 	if (PTL_GETREGS(t, tid, grs) != 0) {
122 		mdb_warn("failed to get current register set");
123 		return (DCMD_ERR);
124 	}
125 
126 	rflags = grs[REG_RFL];
127 
128 	mdb_printf("%%rax = 0x%0?p\t%%r8  = 0x%0?p\n",
129 	    grs[REG_RAX], grs[REG_R8]);
130 	mdb_printf("%%rbx = 0x%0?p\t%%r9  = 0x%0?p\n",
131 	    grs[REG_RBX], grs[REG_R9]);
132 	mdb_printf("%%rcx = 0x%0?p\t%%r10 = 0x%0?p\n",
133 	    grs[REG_RCX], grs[REG_R10]);
134 	mdb_printf("%%rdx = 0x%0?p\t%%r11 = 0x%0?p\n",
135 	    grs[REG_RDX], grs[REG_R11]);
136 	mdb_printf("%%rsi = 0x%0?p\t%%r12 = 0x%0?p\n",
137 	    grs[REG_RSI], grs[REG_R12]);
138 	mdb_printf("%%rdi = 0x%0?p\t%%r13 = 0x%0?p\n",
139 	    grs[REG_RDI], grs[REG_R13]);
140 	mdb_printf("         %?s\t%%r14 = 0x%0?p\n",
141 	    "", grs[REG_R14]);
142 	mdb_printf("         %?s\t%%r15 = 0x%0?p\n",
143 	    "", grs[REG_R15]);
144 
145 	mdb_printf("\n");
146 
147 	mdb_printf("%%cs = 0x%04x\t%%fs = 0x%04x\t%%gs = 0x%04x\n",
148 	    grs[REG_CS], grs[REG_FS], grs[REG_GS]);
149 	mdb_printf("%%ds = 0x%04x\t%%es = 0x%04x\t%%ss = 0x%04x\n",
150 	    grs[REG_DS], grs[REG_ES], grs[REG_SS]);
151 
152 	mdb_printf("\n");
153 
154 	mdb_printf("%%rip = 0x%0?p %A\n", grs[REG_RIP], grs[REG_RIP]);
155 	mdb_printf("%%rbp = 0x%0?p\n", grs[REG_RBP], grs[REG_RBP]);
156 	mdb_printf("%%rsp = 0x%0?p\n", grs[REG_RSP], grs[REG_RSP]);
157 
158 	mdb_printf("\n");
159 
160 	mdb_printf("%%rflags = 0x%08x\n", rflags);
161 
162 	mdb_printf("  id=%u vip=%u vif=%u ac=%u vm=%u rf=%u nt=%u iopl=0x%x\n",
163 	    (rflags & KREG_EFLAGS_ID_MASK) >> KREG_EFLAGS_ID_SHIFT,
164 	    (rflags & KREG_EFLAGS_VIP_MASK) >> KREG_EFLAGS_VIP_SHIFT,
165 	    (rflags & KREG_EFLAGS_VIF_MASK) >> KREG_EFLAGS_VIF_SHIFT,
166 	    (rflags & KREG_EFLAGS_AC_MASK) >> KREG_EFLAGS_AC_SHIFT,
167 	    (rflags & KREG_EFLAGS_VM_MASK) >> KREG_EFLAGS_VM_SHIFT,
168 	    (rflags & KREG_EFLAGS_RF_MASK) >> KREG_EFLAGS_RF_SHIFT,
169 	    (rflags & KREG_EFLAGS_NT_MASK) >> KREG_EFLAGS_NT_SHIFT,
170 	    (rflags & KREG_EFLAGS_IOPL_MASK) >> KREG_EFLAGS_IOPL_SHIFT);
171 
172 	mdb_printf("  status=<%s,%s,%s,%s,%s,%s,%s,%s,%s>\n",
173 	    (rflags & KREG_EFLAGS_OF_MASK) ? "OF" : "of",
174 	    (rflags & KREG_EFLAGS_DF_MASK) ? "DF" : "df",
175 	    (rflags & KREG_EFLAGS_IF_MASK) ? "IF" : "if",
176 	    (rflags & KREG_EFLAGS_TF_MASK) ? "TF" : "tf",
177 	    (rflags & KREG_EFLAGS_SF_MASK) ? "SF" : "sf",
178 	    (rflags & KREG_EFLAGS_ZF_MASK) ? "ZF" : "zf",
179 	    (rflags & KREG_EFLAGS_AF_MASK) ? "AF" : "af",
180 	    (rflags & KREG_EFLAGS_PF_MASK) ? "PF" : "pf",
181 	    (rflags & KREG_EFLAGS_CF_MASK) ? "CF" : "cf");
182 
183 	mdb_printf("\n");
184 
185 	mdb_printf("%%gsbase = 0x%0?p\n", grs[REG_GSBASE]);
186 	mdb_printf("%%fsbase = 0x%0?p\n", grs[REG_FSBASE]);
187 	mdb_printf("%%trapno = 0x%x\n", grs[REG_TRAPNO]);
188 	mdb_printf("   %%err = 0x%x\n", grs[REG_ERR]);
189 
190 	return (set_errno(ENOTSUP));
191 }
192 
193 static const char *
194 fpcw2str(uint32_t cw, char *buf, size_t nbytes)
195 {
196 	char *end = buf + nbytes;
197 	char *p = buf;
198 
199 	buf[0] = '\0';
200 
201 	/*
202 	 * Decode all masks in the 80387 control word.
203 	 */
204 	if (cw & FPIM)
205 		p += mdb_snprintf(p, (size_t)(end - p), "|IM");
206 	if (cw & FPDM)
207 		p += mdb_snprintf(p, (size_t)(end - p), "|DM");
208 	if (cw & FPZM)
209 		p += mdb_snprintf(p, (size_t)(end - p), "|ZM");
210 	if (cw & FPOM)
211 		p += mdb_snprintf(p, (size_t)(end - p), "|OM");
212 	if (cw & FPUM)
213 		p += mdb_snprintf(p, (size_t)(end - p), "|UM");
214 	if (cw & FPPM)
215 		p += mdb_snprintf(p, (size_t)(end - p), "|PM");
216 	if (cw & FPPC)
217 		p += mdb_snprintf(p, (size_t)(end - p), "|PC");
218 	if (cw & FPRC)
219 		p += mdb_snprintf(p, (size_t)(end - p), "|RC");
220 	if (cw & FPIC)
221 		p += mdb_snprintf(p, (size_t)(end - p), "|IC");
222 
223 	/*
224 	 * Decode precision, rounding, and infinity options in control word.
225 	 */
226 	if (cw & FPSIG24)
227 		p += mdb_snprintf(p, (size_t)(end - p), "|SIG24");
228 	if (cw & FPSIG53)
229 		p += mdb_snprintf(p, (size_t)(end - p), "|SIG53");
230 	if (cw & FPSIG64)
231 		p += mdb_snprintf(p, (size_t)(end - p), "|SIG64");
232 
233 	if ((cw & FPRC) == (FPRD|FPRU))
234 		p += mdb_snprintf(p, (size_t)(end - p), "|RTZ");
235 	else if (cw & FPRD)
236 		p += mdb_snprintf(p, (size_t)(end - p), "|RD");
237 	else if (cw & FPRU)
238 		p += mdb_snprintf(p, (size_t)(end - p), "|RU");
239 	else
240 		p += mdb_snprintf(p, (size_t)(end - p), "|RTN");
241 
242 	if (cw & FPA)
243 		p += mdb_snprintf(p, (size_t)(end - p), "|A");
244 	else
245 		p += mdb_snprintf(p, (size_t)(end - p), "|P");
246 	if (cw & WFPB17)
247 		p += mdb_snprintf(p, (size_t)(end - p), "|WFPB17");
248 	if (cw & WFPB24)
249 		p += mdb_snprintf(p, (size_t)(end - p), "|WFPB24");
250 
251 	if (buf[0] == '|')
252 		return (buf + 1);
253 
254 	return ("0");
255 }
256 
257 static const char *
258 fpsw2str(uint32_t cw, char *buf, size_t nbytes)
259 {
260 	char *end = buf + nbytes;
261 	char *p = buf;
262 
263 	buf[0] = '\0';
264 
265 	/*
266 	 * Decode all masks in the 80387 status word.
267 	 */
268 	if (cw & FPS_IE)
269 		p += mdb_snprintf(p, (size_t)(end - p), "|IE");
270 	if (cw & FPS_DE)
271 		p += mdb_snprintf(p, (size_t)(end - p), "|DE");
272 	if (cw & FPS_ZE)
273 		p += mdb_snprintf(p, (size_t)(end - p), "|ZE");
274 	if (cw & FPS_OE)
275 		p += mdb_snprintf(p, (size_t)(end - p), "|OE");
276 	if (cw & FPS_UE)
277 		p += mdb_snprintf(p, (size_t)(end - p), "|UE");
278 	if (cw & FPS_PE)
279 		p += mdb_snprintf(p, (size_t)(end - p), "|PE");
280 	if (cw & FPS_SF)
281 		p += mdb_snprintf(p, (size_t)(end - p), "|SF");
282 	if (cw & FPS_ES)
283 		p += mdb_snprintf(p, (size_t)(end - p), "|ES");
284 	if (cw & FPS_C0)
285 		p += mdb_snprintf(p, (size_t)(end - p), "|C0");
286 	if (cw & FPS_C1)
287 		p += mdb_snprintf(p, (size_t)(end - p), "|C1");
288 	if (cw & FPS_C2)
289 		p += mdb_snprintf(p, (size_t)(end - p), "|C2");
290 	if (cw & FPS_C3)
291 		p += mdb_snprintf(p, (size_t)(end - p), "|C3");
292 	if (cw & FPS_B)
293 		p += mdb_snprintf(p, (size_t)(end - p), "|B");
294 
295 	if (buf[0] == '|')
296 		return (buf + 1);
297 
298 	return ("0");
299 }
300 
301 static const char *
302 fpmxcsr2str(uint32_t mxcsr, char *buf, size_t nbytes)
303 {
304 	char *end = buf + nbytes;
305 	char *p = buf;
306 
307 	buf[0] = '\0';
308 
309 	/*
310 	 * Decode the MXCSR word
311 	 */
312 	if (mxcsr & SSE_IE)
313 		p += mdb_snprintf(p, (size_t)(end - p), "|IE");
314 	if (mxcsr & SSE_DE)
315 		p += mdb_snprintf(p, (size_t)(end - p), "|DE");
316 	if (mxcsr & SSE_ZE)
317 		p += mdb_snprintf(p, (size_t)(end - p), "|ZE");
318 	if (mxcsr & SSE_OE)
319 		p += mdb_snprintf(p, (size_t)(end - p), "|OE");
320 	if (mxcsr & SSE_UE)
321 		p += mdb_snprintf(p, (size_t)(end - p), "|UE");
322 	if (mxcsr & SSE_PE)
323 		p += mdb_snprintf(p, (size_t)(end - p), "|PE");
324 
325 	if (mxcsr & SSE_DAZ)
326 		p += mdb_snprintf(p, (size_t)(end - p), "|DAZ");
327 
328 	if (mxcsr & SSE_IM)
329 		p += mdb_snprintf(p, (size_t)(end - p), "|IM");
330 	if (mxcsr & SSE_DM)
331 		p += mdb_snprintf(p, (size_t)(end - p), "|DM");
332 	if (mxcsr & SSE_ZM)
333 		p += mdb_snprintf(p, (size_t)(end - p), "|ZM");
334 	if (mxcsr & SSE_OM)
335 		p += mdb_snprintf(p, (size_t)(end - p), "|OM");
336 	if (mxcsr & SSE_UM)
337 		p += mdb_snprintf(p, (size_t)(end - p), "|UM");
338 	if (mxcsr & SSE_PM)
339 		p += mdb_snprintf(p, (size_t)(end - p), "|PM");
340 
341 	if ((mxcsr & SSE_RC) == (SSE_RD|SSE_RU))
342 		p += mdb_snprintf(p, (size_t)(end - p), "|RTZ");
343 	else if (mxcsr & SSE_RD)
344 		p += mdb_snprintf(p, (size_t)(end - p), "|RD");
345 	else if (mxcsr & SSE_RU)
346 		p += mdb_snprintf(p, (size_t)(end - p), "|RU");
347 	else
348 		p += mdb_snprintf(p, (size_t)(end - p), "|RTN");
349 
350 	if (mxcsr & SSE_FZ)
351 		p += mdb_snprintf(p, (size_t)(end - p), "|FZ");
352 
353 	if (buf[0] == '|')
354 		return (buf + 1);
355 	return ("0");
356 }
357 
358 /*ARGSUSED*/
359 int
360 pt_fpregs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
361 {
362 	mdb_tgt_t *t = mdb.m_target;
363 	mdb_tgt_tid_t tid;
364 	prfpregset_t fprs;
365 	struct fpchip_state fps;
366 	char buf[256];
367 	uint_t top;
368 	int i;
369 
370 	/*
371 	 * Union for overlaying _fpreg structure on to quad-precision
372 	 * floating-point value (long double).
373 	 */
374 	union {
375 		struct _fpreg reg;
376 		long double ld;
377 	} fpru;
378 
379 	/*
380 	 * Array of strings corresponding to FPU tag word values (see
381 	 * section 7.3.6 of the Intel Programmer's Reference Manual).
382 	 */
383 	const char *tag_strings[] = { "valid", "zero", "special", "empty" };
384 
385 	if (argc != 0)
386 		return (DCMD_USAGE);
387 
388 	if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_UNDEAD) {
389 		mdb_warn("no process active\n");
390 		return (DCMD_ERR);
391 	}
392 
393 	if (Pstate(t->t_pshandle) == PS_LOST) {
394 		mdb_warn("debugger has lost control of process\n");
395 		return (DCMD_ERR);
396 	}
397 
398 	if (flags & DCMD_ADDRSPEC)
399 		tid = (mdb_tgt_tid_t)addr;
400 	else
401 		tid = PTL_TID(t);
402 
403 	mdb_printf("AMD64 (80486 chip with SSE)\n");
404 
405 	if (PTL_GETFPREGS(t, tid, &fprs) != 0) {
406 		mdb_warn("failed to get floating point registers");
407 		return (DCMD_ERR);
408 	}
409 
410 	bcopy(&fprs.fp_reg_set.fpchip_state, &fps, sizeof (fps));
411 
412 	fps.status &= 0xffff;	/* saved status word is really 16 bits */
413 
414 	mdb_printf("cw     0x%04x (%s)\n", fps.cw,
415 	    fpcw2str(fps.cw, buf, sizeof (buf)));
416 
417 	top = (fps.sw & FPS_TOP) >> 11;
418 	mdb_printf("sw     0x%04x (TOP=0t%u) (%s)\n", fps.sw,
419 	    top, fpsw2str(fps.sw, buf, sizeof (buf)));
420 
421 	mdb_printf("xcp sw 0x%04x (%s)\n\n", fps.status,
422 	    fpsw2str(fps.status, buf, sizeof (buf)));
423 
424 	mdb_printf("fop    0x%x\n", fps.fop);
425 	mdb_printf("rip    0x%x\n", fps.rip);
426 	mdb_printf("rdp    0x%x\n\n", fps.rdp);
427 
428 	for (i = 0; i < 8; i++) {
429 		/*
430 		 * Recall that we need to use the current TOP-of-stack value to
431 		 * associate the _st[] index back to a physical register number,
432 		 * since tag word indices are physical register numbers.  Then
433 		 * to get the tag value, we shift over two bits for each tag
434 		 * index, and then grab the bottom two bits.
435 		 */
436 		uint_t tag_index = (i + top) & 7;
437 		uint_t tag_fctw = (fps.fctw >> tag_index) & 1;
438 		uint_t tag_value;
439 		uint_t exp;
440 
441 		/*
442 		 * AMD64 stores the tag in a compressed form. It is
443 		 * necessary to extract the original 2-bit tag value.
444 		 * See AMD64 Architecture Programmer's Manual Volume 2:
445 		 * System Programming, Chapter 11.
446 		 */
447 
448 		fpru.ld = fps.st[i].__fpr_pad._q;
449 		exp = fpru.reg.exponent & 0x7fff;
450 
451 		if (tag_fctw == 0) {
452 			tag_value = 3; /* empty */
453 		} else if (exp == 0) {
454 			if (fpru.reg.significand[0] == 0 &&
455 			    fpru.reg.significand[1] == 0 &&
456 			    fpru.reg.significand[2] == 0 &&
457 			    fpru.reg.significand[3] == 0)
458 				tag_value = 1; /* zero */
459 			else
460 				tag_value = 2; /* special: denormal */
461 		} else if (exp == 0x7fff) {
462 			tag_value = 2; /* special: infinity or NaN */
463 		} else if (fpru.reg.significand[3] & 0x8000) {
464 			tag_value = 0; /* valid */
465 		} else {
466 			tag_value = 2; /* special: unnormal */
467 		}
468 
469 		mdb_printf("%%st%d   0x%04x.%04x%04x%04x%04x = %lg %s\n",
470 		    i, fpru.reg.exponent,
471 		    fpru.reg.significand[3], fpru.reg.significand[2],
472 		    fpru.reg.significand[1], fpru.reg.significand[0],
473 		    fpru.ld, tag_strings[tag_value]);
474 	}
475 
476 	mdb_printf("\nmxcsr  0x%04x (%s)\n", fps.mxcsr,
477 	    fpmxcsr2str(fps.mxcsr, buf, sizeof (buf)));
478 	mdb_printf("xcp    0x%04x (%s)\n\n", fps.xstatus,
479 	    fpmxcsr2str(fps.xstatus, buf, sizeof (buf)));
480 
481 	for (i = 0; i < 8; i++)
482 		mdb_printf("%%xmm%d  0x%08x%08x%08x%08x\n", i,
483 		    fps.xmm[i]._l[3], fps.xmm[i]._l[2],
484 		    fps.xmm[i]._l[1], fps.xmm[i]._l[0]);
485 
486 	return (DCMD_OK);
487 }
488 
489 /*ARGSUSED*/
490 int
491 pt_getfpreg(mdb_tgt_t *t, mdb_tgt_tid_t tid, ushort_t rd_num,
492     ushort_t rd_flags, mdb_tgt_reg_t *rp)
493 {
494 	return (set_errno(ENOTSUP));
495 }
496 
497 /*ARGSUSED*/
498 int
499 pt_putfpreg(mdb_tgt_t *t, mdb_tgt_tid_t tid, ushort_t rd_num,
500     ushort_t rd_flags, mdb_tgt_reg_t rval)
501 {
502 	return (set_errno(ENOTSUP));
503 }
504 
505 /*ARGSUSED*/
506 void
507 pt_addfpregs(mdb_tgt_t *t)
508 {
509 	/* not implemented */
510 }
511 
512 /*ARGSUSED*/
513 int
514 pt_frameregs(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
515     const mdb_tgt_gregset_t *gregs, boolean_t pc_faked)
516 {
517 	return (set_errno(ENOTSUP));
518 }
519 
520 /*ARGSUSED*/
521 const char *
522 pt_disasm(const GElf_Ehdr *ehp)
523 {
524 	return ("amd64");
525 }
526 
527 /*
528  * Determine the return address for the current frame.
529  */
530 int
531 pt_step_out(mdb_tgt_t *t, uintptr_t *p)
532 {
533 	const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
534 
535 	if (Pstate(t->t_pshandle) != PS_STOP)
536 		return (set_errno(EMDB_TGTBUSY));
537 
538 	return (mdb_amd64_step_out(t, p, psp->pr_reg[EIP], psp->pr_reg[EBP],
539 	    psp->pr_reg[UESP], psp->pr_instr));
540 }
541 
542 /*
543  * Return the address of the next instruction following a call, or return -1
544  * and set errno to EAGAIN if the target should just single-step.
545  */
546 int
547 pt_next(mdb_tgt_t *t, uintptr_t *p)
548 {
549 	const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
550 
551 	if (Pstate(t->t_pshandle) != PS_STOP)
552 		return (set_errno(EMDB_TGTBUSY));
553 
554 	return (mdb_amd64_next(t, p, psp->pr_reg[REG_RIP], pt_read_instr(t)));
555 }
556