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  * Copyright (c) 2018, Joyent, Inc.
28  * Copyright 2019 Doma Gergő Mihály <doma.gergo.mihaly@gmail.com>
29  * Copyright 2023 Oxide Computer Company
30  */
31 
32 /*
33  * User Process Target Intel 64-bit component
34  *
35  * This file provides the ISA-dependent portion of the user process target.
36  * For more details on the implementation refer to mdb_proc.c.
37  */
38 
39 #include <mdb/mdb_proc.h>
40 #include <mdb/mdb_kreg.h>
41 #include <mdb/mdb_err.h>
42 #include <mdb/mdb_isautil.h>
43 #include <mdb/mdb_amd64util.h>
44 #include <mdb/proc_x86util.h>
45 #include <mdb/mdb.h>
46 
47 #include <sys/ucontext.h>
48 #include <sys/frame.h>
49 #include <libproc.h>
50 #include <sys/fp.h>
51 #include <ieeefp.h>
52 #include <sys/sysmacros.h>
53 
54 #include <stddef.h>
55 
56 const mdb_tgt_regdesc_t pt_regdesc[] = {
57 	{ "r15",	REG_R15,	MDB_TGT_R_EXPORT },
58 	{ "r15d",	REG_R15,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
59 	{ "r15w",	REG_R15,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
60 	{ "r15l",	REG_R15,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
61 	{ "r14",	REG_R14,	MDB_TGT_R_EXPORT },
62 	{ "r14d",	REG_R14,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
63 	{ "r14w",	REG_R14,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
64 	{ "r14l",	REG_R14,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
65 	{ "r13",	REG_R13,	MDB_TGT_R_EXPORT },
66 	{ "r13d",	REG_R13,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
67 	{ "r13w",	REG_R13,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
68 	{ "r13l",	REG_R13,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
69 	{ "r12",	REG_R12,	MDB_TGT_R_EXPORT },
70 	{ "r12d",	REG_R12,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
71 	{ "r12w",	REG_R12,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
72 	{ "r12l",	REG_R12,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
73 	{ "r11",	REG_R11,	MDB_TGT_R_EXPORT },
74 	{ "r11d",	REG_R11,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
75 	{ "r11w",	REG_R11,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
76 	{ "r11l",	REG_R11,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
77 	{ "r10",	REG_R10,	MDB_TGT_R_EXPORT },
78 	{ "r10d",	REG_R10,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
79 	{ "r10w",	REG_R10,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
80 	{ "r10l",	REG_R10,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
81 	{ "r9",		REG_R9,		MDB_TGT_R_EXPORT },
82 	{ "r9d",	REG_R9,		MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
83 	{ "r9w",	REG_R9,		MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
84 	{ "r9l",	REG_R9,		MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
85 	{ "r8",		REG_R8,		MDB_TGT_R_EXPORT },
86 	{ "r8d",	REG_R8,		MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
87 	{ "r8w",	REG_R8,		MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
88 	{ "r8l",	REG_R8,		MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
89 	{ "rdi",	REG_RDI,	MDB_TGT_R_EXPORT },
90 	{ "edi",	REG_RDI,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
91 	{ "di",		REG_RDI,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
92 	{ "dil",	REG_RDI,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
93 	{ "rsi",	REG_RSI,	MDB_TGT_R_EXPORT },
94 	{ "esi",	REG_RSI,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
95 	{ "si",		REG_RSI,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
96 	{ "sil",	REG_RSI,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
97 	{ "rbp",	REG_RBP,	MDB_TGT_R_EXPORT },
98 	{ "ebp",	REG_RBP,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
99 	{ "bp",		REG_RBP,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
100 	{ "bpl",	REG_RBP,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
101 	{ "rbx",	REG_RBX,	MDB_TGT_R_EXPORT },
102 	{ "ebx",	REG_RBX,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
103 	{ "bx",		REG_RBX,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
104 	{ "bh",		REG_RBX,	MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
105 	{ "bl",		REG_RBX,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
106 	{ "rdx",	REG_RDX,	MDB_TGT_R_EXPORT },
107 	{ "edx",	REG_RDX,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
108 	{ "dx",		REG_RDX,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
109 	{ "dh",		REG_RDX,	MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
110 	{ "dl",		REG_RDX,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
111 	{ "rcx",	REG_RCX,	MDB_TGT_R_EXPORT },
112 	{ "ecx",	REG_RCX,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
113 	{ "cx",		REG_RCX,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
114 	{ "ch",		REG_RCX,	MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
115 	{ "cl",		REG_RCX,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
116 	{ "rax",	REG_RAX,	MDB_TGT_R_EXPORT },
117 	{ "eax",	REG_RAX,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
118 	{ "ax",		REG_RAX,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
119 	{ "ah",		REG_RAX,	MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
120 	{ "al",		REG_RAX,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
121 	{ "trapno",	REG_TRAPNO,	MDB_TGT_R_EXPORT },
122 	{ "err",	REG_ERR,	MDB_TGT_R_EXPORT },
123 	{ "rip",	REG_RIP,	MDB_TGT_R_EXPORT },
124 	{ "cs",		REG_CS,		MDB_TGT_R_EXPORT },
125 	{ "rflags",	REG_RFL,	MDB_TGT_R_EXPORT },
126 	{ "eflags",	REG_RFL,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
127 	{ "rsp",	REG_RSP,	MDB_TGT_R_EXPORT },
128 	{ "esp",	REG_RSP,	MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
129 	{ "sp",		REG_RSP,	MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
130 	{ "spl",	REG_RSP,	MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
131 	{ "ss",		REG_SS,		MDB_TGT_R_EXPORT },
132 	{ "fs",		REG_FS,		MDB_TGT_R_EXPORT },
133 	{ "gs",		REG_GS,		MDB_TGT_R_EXPORT },
134 	{ "es",		REG_ES,		MDB_TGT_R_EXPORT },
135 	{ "ds",		REG_DS,		MDB_TGT_R_EXPORT },
136 	{ "fsbase",	REG_FSBASE,	MDB_TGT_R_EXPORT },
137 	{ "gsbase",	REG_GSBASE,	MDB_TGT_R_EXPORT },
138 	{ NULL, 0, 0 }
139 };
140 
141 /*
142  * We cannot rely on pr_instr, because if we hit a breakpoint or the user has
143  * artifically modified memory, it will no longer be correct.
144  */
145 static uint8_t
pt_read_instr(mdb_tgt_t * t)146 pt_read_instr(mdb_tgt_t *t)
147 {
148 	const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
149 	uint8_t ret = 0;
150 
151 	(void) mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, &ret, sizeof (ret),
152 	    psp->pr_reg[REG_RIP]);
153 
154 	return (ret);
155 }
156 
157 /*ARGSUSED*/
158 int
pt_regs(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)159 pt_regs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
160 {
161 	mdb_tgt_t *t = mdb.m_target;
162 	mdb_tgt_tid_t tid;
163 	prgregset_t grs;
164 	prgreg_t rflags;
165 	boolean_t from_ucontext = B_FALSE;
166 
167 	if (mdb_getopts(argc, argv,
168 	    'u', MDB_OPT_SETBITS, B_TRUE, &from_ucontext, NULL) != argc) {
169 		return (DCMD_USAGE);
170 	}
171 
172 	if (from_ucontext) {
173 		int off;
174 		int o0, o1;
175 
176 		if (!(flags & DCMD_ADDRSPEC)) {
177 			mdb_warn("-u requires a ucontext_t address\n");
178 			return (DCMD_ERR);
179 		}
180 
181 		o0 = mdb_ctf_offsetof_by_name("ucontext_t", "uc_mcontext");
182 		o1 = mdb_ctf_offsetof_by_name("mcontext_t", "gregs");
183 		if (o0 == -1 || o1 == -1) {
184 			off = offsetof(ucontext_t, uc_mcontext) +
185 			    offsetof(mcontext_t, gregs);
186 		} else {
187 			off = o0 + o1;
188 		}
189 
190 		if (mdb_vread(&grs, sizeof (grs), addr + off) != sizeof (grs)) {
191 			mdb_warn("failed to read from ucontext_t %p", addr);
192 			return (DCMD_ERR);
193 		}
194 		goto print_regs;
195 	}
196 
197 	if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_UNDEAD) {
198 		mdb_warn("no process active\n");
199 		return (DCMD_ERR);
200 	}
201 
202 	if (Pstate(t->t_pshandle) == PS_LOST) {
203 		mdb_warn("debugger has lost control of process\n");
204 		return (DCMD_ERR);
205 	}
206 
207 	if (flags & DCMD_ADDRSPEC)
208 		tid = (mdb_tgt_tid_t)addr;
209 	else
210 		tid = PTL_TID(t);
211 
212 	if (PTL_GETREGS(t, tid, grs) != 0) {
213 		mdb_warn("failed to get current register set");
214 		return (DCMD_ERR);
215 	}
216 
217 print_regs:
218 	rflags = grs[REG_RFL];
219 
220 	mdb_printf("%%rax = 0x%0?p\t%%r8  = 0x%0?p\n",
221 	    grs[REG_RAX], grs[REG_R8]);
222 	mdb_printf("%%rbx = 0x%0?p\t%%r9  = 0x%0?p\n",
223 	    grs[REG_RBX], grs[REG_R9]);
224 	mdb_printf("%%rcx = 0x%0?p\t%%r10 = 0x%0?p\n",
225 	    grs[REG_RCX], grs[REG_R10]);
226 	mdb_printf("%%rdx = 0x%0?p\t%%r11 = 0x%0?p\n",
227 	    grs[REG_RDX], grs[REG_R11]);
228 	mdb_printf("%%rsi = 0x%0?p\t%%r12 = 0x%0?p\n",
229 	    grs[REG_RSI], grs[REG_R12]);
230 	mdb_printf("%%rdi = 0x%0?p\t%%r13 = 0x%0?p\n",
231 	    grs[REG_RDI], grs[REG_R13]);
232 	mdb_printf("         %?s\t%%r14 = 0x%0?p\n",
233 	    "", grs[REG_R14]);
234 	mdb_printf("         %?s\t%%r15 = 0x%0?p\n",
235 	    "", grs[REG_R15]);
236 
237 	mdb_printf("\n");
238 
239 	mdb_printf("%%cs = 0x%04x\t%%fs = 0x%04x\t%%gs = 0x%04x\n",
240 	    grs[REG_CS], grs[REG_FS], grs[REG_GS]);
241 	mdb_printf("%%ds = 0x%04x\t%%es = 0x%04x\t%%ss = 0x%04x\n",
242 	    grs[REG_DS], grs[REG_ES], grs[REG_SS]);
243 
244 	mdb_printf("\n");
245 
246 	mdb_printf("%%rip = 0x%0?p %A\n", grs[REG_RIP], grs[REG_RIP]);
247 	mdb_printf("%%rbp = 0x%0?p\n", grs[REG_RBP], grs[REG_RBP]);
248 	mdb_printf("%%rsp = 0x%0?p\n", grs[REG_RSP], grs[REG_RSP]);
249 
250 	mdb_printf("\n");
251 
252 	mdb_printf("%%rflags = 0x%08x\n", rflags);
253 
254 	mdb_printf("  id=%u vip=%u vif=%u ac=%u vm=%u rf=%u nt=%u iopl=0x%x\n",
255 	    (rflags & KREG_EFLAGS_ID_MASK) >> KREG_EFLAGS_ID_SHIFT,
256 	    (rflags & KREG_EFLAGS_VIP_MASK) >> KREG_EFLAGS_VIP_SHIFT,
257 	    (rflags & KREG_EFLAGS_VIF_MASK) >> KREG_EFLAGS_VIF_SHIFT,
258 	    (rflags & KREG_EFLAGS_AC_MASK) >> KREG_EFLAGS_AC_SHIFT,
259 	    (rflags & KREG_EFLAGS_VM_MASK) >> KREG_EFLAGS_VM_SHIFT,
260 	    (rflags & KREG_EFLAGS_RF_MASK) >> KREG_EFLAGS_RF_SHIFT,
261 	    (rflags & KREG_EFLAGS_NT_MASK) >> KREG_EFLAGS_NT_SHIFT,
262 	    (rflags & KREG_EFLAGS_IOPL_MASK) >> KREG_EFLAGS_IOPL_SHIFT);
263 
264 	mdb_printf("  status=<%s,%s,%s,%s,%s,%s,%s,%s,%s>\n",
265 	    (rflags & KREG_EFLAGS_OF_MASK) ? "OF" : "of",
266 	    (rflags & KREG_EFLAGS_DF_MASK) ? "DF" : "df",
267 	    (rflags & KREG_EFLAGS_IF_MASK) ? "IF" : "if",
268 	    (rflags & KREG_EFLAGS_TF_MASK) ? "TF" : "tf",
269 	    (rflags & KREG_EFLAGS_SF_MASK) ? "SF" : "sf",
270 	    (rflags & KREG_EFLAGS_ZF_MASK) ? "ZF" : "zf",
271 	    (rflags & KREG_EFLAGS_AF_MASK) ? "AF" : "af",
272 	    (rflags & KREG_EFLAGS_PF_MASK) ? "PF" : "pf",
273 	    (rflags & KREG_EFLAGS_CF_MASK) ? "CF" : "cf");
274 
275 	mdb_printf("\n");
276 
277 	mdb_printf("%%gsbase = 0x%0?p\n", grs[REG_GSBASE]);
278 	mdb_printf("%%fsbase = 0x%0?p\n", grs[REG_FSBASE]);
279 	mdb_printf("%%trapno = 0x%x\n", grs[REG_TRAPNO]);
280 	mdb_printf("   %%err = 0x%x\n", grs[REG_ERR]);
281 
282 	return (set_errno(ENOTSUP));
283 }
284 
285 int
pt_fpregs(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)286 pt_fpregs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
287 {
288 	int ret;
289 	prfpregset_t fprs;
290 	struct _fpchip_state fps;
291 	char buf[256];
292 	uint_t top;
293 	size_t i;
294 
295 	/*
296 	 * Union for overlaying _fpreg structure on to quad-precision
297 	 * floating-point value (long double).
298 	 */
299 	union {
300 		struct _fpreg reg;
301 		long double ld;
302 	} fpru;
303 
304 	/*
305 	 * We use common code between 32-bit and 64-bit x86 to capture and print
306 	 * the extended vector state. The remaining classic 387 state is
307 	 * finicky and different enough that it is left to be dealt with on its
308 	 * own.
309 	 */
310 	if ((ret = x86_pt_fpregs_common(addr, flags, argc, &fprs)) != DCMD_OK)
311 		return (ret);
312 
313 	bcopy(&fprs.fp_reg_set.fpchip_state, &fps, sizeof (fps));
314 	mdb_printf("387 and FP Control State\n");
315 
316 	fps.status &= 0xffff;	/* saved status word is really 16 bits */
317 
318 	mdb_printf("cw     0x%04x (%s)\n", fps.cw,
319 	    fpcw2str(fps.cw, buf, sizeof (buf)));
320 
321 	top = (fps.sw & FPS_TOP) >> 11;
322 	mdb_printf("sw     0x%04x (TOP=0t%u) (%s)\n", fps.sw,
323 	    top, fpsw2str(fps.sw, buf, sizeof (buf)));
324 
325 	mdb_printf("xcp sw 0x%04x (%s)\n\n", fps.status,
326 	    fpsw2str(fps.status, buf, sizeof (buf)));
327 
328 	mdb_printf("fop    0x%x\n", fps.fop);
329 	mdb_printf("rip    0x%x\n", fps.rip);
330 	mdb_printf("rdp    0x%x\n\n", fps.rdp);
331 
332 	for (i = 0; i < ARRAY_SIZE(fps.st); i++) {
333 		/*
334 		 * Recall that we need to use the current TOP-of-stack value to
335 		 * associate the _st[] index back to a physical register number,
336 		 * since tag word indices are physical register numbers.  Then
337 		 * to get the tag value, we shift over two bits for each tag
338 		 * index, and then grab the bottom two bits.
339 		 */
340 		uint_t tag_index = (i + top) & 7;
341 		uint_t tag_fctw = (fps.fctw >> tag_index) & 1;
342 		uint_t tag_value;
343 		uint_t exp;
344 
345 		/*
346 		 * AMD64 stores the tag in a compressed form. It is
347 		 * necessary to extract the original 2-bit tag value.
348 		 * See AMD64 Architecture Programmer's Manual Volume 2:
349 		 * System Programming, Chapter 11.
350 		 */
351 
352 		fpru.ld = fps.st[i].__fpr_pad._q;
353 		exp = fpru.reg.exponent & 0x7fff;
354 
355 		if (tag_fctw == 0) {
356 			tag_value = 3; /* empty */
357 		} else if (exp == 0) {
358 			if (fpru.reg.significand[0] == 0 &&
359 			    fpru.reg.significand[1] == 0 &&
360 			    fpru.reg.significand[2] == 0 &&
361 			    fpru.reg.significand[3] == 0)
362 				tag_value = 1; /* zero */
363 			else
364 				tag_value = 2; /* special: denormal */
365 		} else if (exp == 0x7fff) {
366 			tag_value = 2; /* special: infinity or NaN */
367 		} else if (fpru.reg.significand[3] & 0x8000) {
368 			tag_value = 0; /* valid */
369 		} else {
370 			tag_value = 2; /* special: unnormal */
371 		}
372 
373 		mdb_printf("%%st%d   0x%04x.%04x%04x%04x%04x = %lg %s\n",
374 		    i, fpru.reg.exponent,
375 		    fpru.reg.significand[3], fpru.reg.significand[2],
376 		    fpru.reg.significand[1], fpru.reg.significand[0],
377 		    fpru.ld, fptag2str(tag_value));
378 	}
379 
380 	x86_pt_fpregs_sse_ctl(fps.mxcsr, fps.xstatus, buf, sizeof (buf));
381 
382 	return (DCMD_OK);
383 }
384 
385 /*ARGSUSED*/
386 int
pt_getfpreg(mdb_tgt_t * t,mdb_tgt_tid_t tid,ushort_t rd_num,ushort_t rd_flags,mdb_tgt_reg_t * rp)387 pt_getfpreg(mdb_tgt_t *t, mdb_tgt_tid_t tid, ushort_t rd_num,
388     ushort_t rd_flags, mdb_tgt_reg_t *rp)
389 {
390 	return (set_errno(ENOTSUP));
391 }
392 
393 /*ARGSUSED*/
394 int
pt_putfpreg(mdb_tgt_t * t,mdb_tgt_tid_t tid,ushort_t rd_num,ushort_t rd_flags,mdb_tgt_reg_t rval)395 pt_putfpreg(mdb_tgt_t *t, mdb_tgt_tid_t tid, ushort_t rd_num,
396     ushort_t rd_flags, mdb_tgt_reg_t rval)
397 {
398 	return (set_errno(ENOTSUP));
399 }
400 
401 /*ARGSUSED*/
402 void
pt_addfpregs(mdb_tgt_t * t)403 pt_addfpregs(mdb_tgt_t *t)
404 {
405 	/* not implemented */
406 }
407 
408 /*ARGSUSED*/
409 int
pt_frameregs(void * arglim,uintptr_t pc,uint_t argc,const long * argv,const mdb_tgt_gregset_t * gregs,boolean_t pc_faked)410 pt_frameregs(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
411     const mdb_tgt_gregset_t *gregs, boolean_t pc_faked)
412 {
413 	return (set_errno(ENOTSUP));
414 }
415 
416 /*ARGSUSED*/
417 const char *
pt_disasm(const GElf_Ehdr * ehp)418 pt_disasm(const GElf_Ehdr *ehp)
419 {
420 	return ("amd64");
421 }
422 
423 /*
424  * Determine the return address for the current frame.
425  */
426 int
pt_step_out(mdb_tgt_t * t,uintptr_t * p)427 pt_step_out(mdb_tgt_t *t, uintptr_t *p)
428 {
429 	const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
430 
431 	if (Pstate(t->t_pshandle) != PS_STOP)
432 		return (set_errno(EMDB_TGTBUSY));
433 
434 	return (mdb_amd64_step_out(t, p, psp->pr_reg[REG_RIP],
435 	    psp->pr_reg[REG_RBP], psp->pr_reg[REG_RSP], psp->pr_instr));
436 }
437 
438 /*
439  * Return the address of the next instruction following a call, or return -1
440  * and set errno to EAGAIN if the target should just single-step.
441  */
442 int
pt_next(mdb_tgt_t * t,uintptr_t * p)443 pt_next(mdb_tgt_t *t, uintptr_t *p)
444 {
445 	const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp;
446 
447 	if (Pstate(t->t_pshandle) != PS_STOP)
448 		return (set_errno(EMDB_TGTBUSY));
449 
450 	return (mdb_amd64_next(t, p, psp->pr_reg[REG_RIP], pt_read_instr(t)));
451 }
452