17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5b2c0fa2eSdmick  * Common Development and Distribution License (the "License").
6b2c0fa2eSdmick  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21b2c0fa2eSdmick 
227c478bd9Sstevel@tonic-gate /*
23ae115bc7Smrj  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
2621072fc3SMarcel Telka /*
2774ecdb51SJohn Levon  * Copyright (c) 2018, Joyent, Inc.  All rights reserved.
280b453801SGordon Ross  * Copyright 2014 Nexenta Systems, Inc.  All rights reserved.
292cb81960SAdam H. Leventhal  * Copyright (c) 2013 by Delphix. All rights reserved.
3021072fc3SMarcel Telka  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/reg.h>
347c478bd9Sstevel@tonic-gate #include <sys/privregs.h>
357c478bd9Sstevel@tonic-gate #include <sys/stack.h>
367c478bd9Sstevel@tonic-gate #include <sys/frame.h>
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate #include <mdb/mdb_target_impl.h>
397c478bd9Sstevel@tonic-gate #include <mdb/mdb_kreg_impl.h>
407c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h>
417c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
42*9c3024a3SHans Rosenfeld #include <mdb/mdb_isautil.h>
437c478bd9Sstevel@tonic-gate #include <mdb/mdb_amd64util.h>
44159eb9e1Ssherrym #include <mdb/mdb_ctf.h>
457c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h>
467c478bd9Sstevel@tonic-gate #include <mdb/mdb.h>
477c478bd9Sstevel@tonic-gate 
482d4be7aaSRichard Lowe #include <saveargs.h>
492d4be7aaSRichard Lowe 
507c478bd9Sstevel@tonic-gate /*
517c478bd9Sstevel@tonic-gate  * This array is used by the getareg and putareg entry points, and also by our
527c478bd9Sstevel@tonic-gate  * register variable discipline.
537c478bd9Sstevel@tonic-gate  */
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate const mdb_tgt_regdesc_t mdb_amd64_kregs[] = {
567c478bd9Sstevel@tonic-gate 	{ "savfp", KREG_SAVFP, MDB_TGT_R_EXPORT },
577c478bd9Sstevel@tonic-gate 	{ "savpc", KREG_SAVPC, MDB_TGT_R_EXPORT },
587c478bd9Sstevel@tonic-gate 	{ "rdi", KREG_RDI, MDB_TGT_R_EXPORT },
590a47c91cSRobert Mustacchi 	{ "edi", KREG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
600a47c91cSRobert Mustacchi 	{ "di",  KREG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
610a47c91cSRobert Mustacchi 	{ "dil", KREG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
627c478bd9Sstevel@tonic-gate 	{ "rsi", KREG_RSI, MDB_TGT_R_EXPORT },
630a47c91cSRobert Mustacchi 	{ "esi", KREG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
640a47c91cSRobert Mustacchi 	{ "si",  KREG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
650a47c91cSRobert Mustacchi 	{ "sil", KREG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
667c478bd9Sstevel@tonic-gate 	{ "rdx", KREG_RDX, MDB_TGT_R_EXPORT },
670a47c91cSRobert Mustacchi 	{ "edx", KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
680a47c91cSRobert Mustacchi 	{ "dx",  KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
690a47c91cSRobert Mustacchi 	{ "dh",  KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
700a47c91cSRobert Mustacchi 	{ "dl",  KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
717c478bd9Sstevel@tonic-gate 	{ "rcx", KREG_RCX, MDB_TGT_R_EXPORT },
720a47c91cSRobert Mustacchi 	{ "ecx", KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
730a47c91cSRobert Mustacchi 	{ "cx",  KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
740a47c91cSRobert Mustacchi 	{ "ch",  KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
750a47c91cSRobert Mustacchi 	{ "cl",  KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
767c478bd9Sstevel@tonic-gate 	{ "r8", KREG_R8, MDB_TGT_R_EXPORT },
770a47c91cSRobert Mustacchi 	{ "r8d", KREG_R8,  MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
780a47c91cSRobert Mustacchi 	{ "r8w", KREG_R8,  MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
790a47c91cSRobert Mustacchi 	{ "r8l", KREG_R8,  MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
807c478bd9Sstevel@tonic-gate 	{ "r9", KREG_R9, MDB_TGT_R_EXPORT },
810a47c91cSRobert Mustacchi 	{ "r9d", KREG_R8,  MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
820a47c91cSRobert Mustacchi 	{ "r9w", KREG_R8,  MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
830a47c91cSRobert Mustacchi 	{ "r9l", KREG_R8,  MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
847c478bd9Sstevel@tonic-gate 	{ "rax", KREG_RAX, MDB_TGT_R_EXPORT },
850a47c91cSRobert Mustacchi 	{ "eax", KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
860a47c91cSRobert Mustacchi 	{ "ax",  KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
870a47c91cSRobert Mustacchi 	{ "ah",  KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
880a47c91cSRobert Mustacchi 	{ "al",  KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
897c478bd9Sstevel@tonic-gate 	{ "rbx", KREG_RBX, MDB_TGT_R_EXPORT },
900a47c91cSRobert Mustacchi 	{ "ebx", KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
910a47c91cSRobert Mustacchi 	{ "bx",  KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
920a47c91cSRobert Mustacchi 	{ "bh",  KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
930a47c91cSRobert Mustacchi 	{ "bl",  KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
947c478bd9Sstevel@tonic-gate 	{ "rbp", KREG_RBP, MDB_TGT_R_EXPORT },
950a47c91cSRobert Mustacchi 	{ "ebp", KREG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
960a47c91cSRobert Mustacchi 	{ "bp",  KREG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
970a47c91cSRobert Mustacchi 	{ "bpl", KREG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
987c478bd9Sstevel@tonic-gate 	{ "r10", KREG_R10, MDB_TGT_R_EXPORT },
990a47c91cSRobert Mustacchi 	{ "r10d", KREG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
1000a47c91cSRobert Mustacchi 	{ "r10w", KREG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
1010a47c91cSRobert Mustacchi 	{ "r10l", KREG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
1027c478bd9Sstevel@tonic-gate 	{ "r11", KREG_R11, MDB_TGT_R_EXPORT },
1030a47c91cSRobert Mustacchi 	{ "r11d", KREG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
1040a47c91cSRobert Mustacchi 	{ "r11w", KREG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
1050a47c91cSRobert Mustacchi 	{ "r11l", KREG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
1067c478bd9Sstevel@tonic-gate 	{ "r12", KREG_R12, MDB_TGT_R_EXPORT },
1070a47c91cSRobert Mustacchi 	{ "r12d", KREG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
1080a47c91cSRobert Mustacchi 	{ "r12w", KREG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
1090a47c91cSRobert Mustacchi 	{ "r12l", KREG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
1107c478bd9Sstevel@tonic-gate 	{ "r13", KREG_R13, MDB_TGT_R_EXPORT },
1110a47c91cSRobert Mustacchi 	{ "r13d", KREG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
1120a47c91cSRobert Mustacchi 	{ "r13w", KREG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
1130a47c91cSRobert Mustacchi 	{ "r13l", KREG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
1147c478bd9Sstevel@tonic-gate 	{ "r14", KREG_R14, MDB_TGT_R_EXPORT },
1150a47c91cSRobert Mustacchi 	{ "r14d", KREG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
1160a47c91cSRobert Mustacchi 	{ "r14w", KREG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
1170a47c91cSRobert Mustacchi 	{ "r14l", KREG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
1187c478bd9Sstevel@tonic-gate 	{ "r15", KREG_R15, MDB_TGT_R_EXPORT },
1190a47c91cSRobert Mustacchi 	{ "r15d", KREG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
1200a47c91cSRobert Mustacchi 	{ "r15w", KREG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
1210a47c91cSRobert Mustacchi 	{ "r15l", KREG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
1227c478bd9Sstevel@tonic-gate 	{ "ds", KREG_DS, MDB_TGT_R_EXPORT },
1237c478bd9Sstevel@tonic-gate 	{ "es", KREG_ES, MDB_TGT_R_EXPORT },
1247c478bd9Sstevel@tonic-gate 	{ "fs", KREG_FS, MDB_TGT_R_EXPORT },
1257c478bd9Sstevel@tonic-gate 	{ "gs", KREG_GS, MDB_TGT_R_EXPORT },
1267c478bd9Sstevel@tonic-gate 	{ "trapno", KREG_TRAPNO, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
1277c478bd9Sstevel@tonic-gate 	{ "err", KREG_ERR, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
1287c478bd9Sstevel@tonic-gate 	{ "rip", KREG_RIP, MDB_TGT_R_EXPORT },
1297c478bd9Sstevel@tonic-gate 	{ "cs", KREG_CS, MDB_TGT_R_EXPORT },
1307c478bd9Sstevel@tonic-gate 	{ "rflags", KREG_RFLAGS, MDB_TGT_R_EXPORT },
1310a47c91cSRobert Mustacchi 	{ "eflags", KREG_RFLAGS, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
1327c478bd9Sstevel@tonic-gate 	{ "rsp", KREG_RSP, MDB_TGT_R_EXPORT },
1330a47c91cSRobert Mustacchi 	{ "esp", KREG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
1340a47c91cSRobert Mustacchi 	{ "sp",  KREG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
1350a47c91cSRobert Mustacchi 	{ "spl", KREG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
1367c478bd9Sstevel@tonic-gate 	{ "ss", KREG_SS, MDB_TGT_R_EXPORT },
13774ecdb51SJohn Levon 	{ "gsbase", KREG_GSBASE, MDB_TGT_R_EXPORT },
13874ecdb51SJohn Levon 	{ "kgsbase", KREG_KGSBASE, MDB_TGT_R_EXPORT },
13974ecdb51SJohn Levon 	{ "cr2", KREG_CR2, MDB_TGT_R_EXPORT },
1405f633405SAlex Wilson 	{ "cr3", KREG_CR3, MDB_TGT_R_EXPORT },
1417c478bd9Sstevel@tonic-gate 	{ NULL, 0, 0 }
1427c478bd9Sstevel@tonic-gate };
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate void
mdb_amd64_printregs(const mdb_tgt_gregset_t * gregs)1457c478bd9Sstevel@tonic-gate mdb_amd64_printregs(const mdb_tgt_gregset_t *gregs)
1467c478bd9Sstevel@tonic-gate {
1477c478bd9Sstevel@tonic-gate 	const kreg_t *kregs = &gregs->kregs[0];
1487c478bd9Sstevel@tonic-gate 	kreg_t rflags = kregs[KREG_RFLAGS];
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate #define	GETREG2(x) ((uintptr_t)kregs[(x)]), ((uintptr_t)kregs[(x)])
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	mdb_printf("%%rax = 0x%0?p %15A %%r9  = 0x%0?p %A\n",
1537c478bd9Sstevel@tonic-gate 	    GETREG2(KREG_RAX), GETREG2(KREG_R9));
1547c478bd9Sstevel@tonic-gate 	mdb_printf("%%rbx = 0x%0?p %15A %%r10 = 0x%0?p %A\n",
1557c478bd9Sstevel@tonic-gate 	    GETREG2(KREG_RBX), GETREG2(KREG_R10));
1567c478bd9Sstevel@tonic-gate 	mdb_printf("%%rcx = 0x%0?p %15A %%r11 = 0x%0?p %A\n",
1577c478bd9Sstevel@tonic-gate 	    GETREG2(KREG_RCX), GETREG2(KREG_R11));
1587c478bd9Sstevel@tonic-gate 	mdb_printf("%%rdx = 0x%0?p %15A %%r12 = 0x%0?p %A\n",
1597c478bd9Sstevel@tonic-gate 	    GETREG2(KREG_RDX), GETREG2(KREG_R12));
1607c478bd9Sstevel@tonic-gate 	mdb_printf("%%rsi = 0x%0?p %15A %%r13 = 0x%0?p %A\n",
1617c478bd9Sstevel@tonic-gate 	    GETREG2(KREG_RSI), GETREG2(KREG_R13));
1627c478bd9Sstevel@tonic-gate 	mdb_printf("%%rdi = 0x%0?p %15A %%r14 = 0x%0?p %A\n",
1637c478bd9Sstevel@tonic-gate 	    GETREG2(KREG_RDI), GETREG2(KREG_R14));
1647c478bd9Sstevel@tonic-gate 	mdb_printf("%%r8  = 0x%0?p %15A %%r15 = 0x%0?p %A\n\n",
1657c478bd9Sstevel@tonic-gate 	    GETREG2(KREG_R8), GETREG2(KREG_R15));
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate 	mdb_printf("%%rip = 0x%0?p %A\n", GETREG2(KREG_RIP));
1687c478bd9Sstevel@tonic-gate 	mdb_printf("%%rbp = 0x%0?p\n", kregs[KREG_RBP]);
1697c478bd9Sstevel@tonic-gate 	mdb_printf("%%rsp = 0x%0?p\n", kregs[KREG_RSP]);
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	mdb_printf("%%rflags = 0x%08x\n", rflags);
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	mdb_printf("  id=%u vip=%u vif=%u ac=%u vm=%u rf=%u nt=%u iopl=0x%x\n",
1747c478bd9Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_ID_MASK) >> KREG_EFLAGS_ID_SHIFT,
1757c478bd9Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_VIP_MASK) >> KREG_EFLAGS_VIP_SHIFT,
1767c478bd9Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_VIF_MASK) >> KREG_EFLAGS_VIF_SHIFT,
1777c478bd9Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_AC_MASK) >> KREG_EFLAGS_AC_SHIFT,
1787c478bd9Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_VM_MASK) >> KREG_EFLAGS_VM_SHIFT,
1797c478bd9Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_RF_MASK) >> KREG_EFLAGS_RF_SHIFT,
1807c478bd9Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_NT_MASK) >> KREG_EFLAGS_NT_SHIFT,
1817c478bd9Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_IOPL_MASK) >> KREG_EFLAGS_IOPL_SHIFT);
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	mdb_printf("  status=<%s,%s,%s,%s,%s,%s,%s,%s,%s>\n\n",
1847c478bd9Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_OF_MASK) ? "OF" : "of",
1857c478bd9Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_DF_MASK) ? "DF" : "df",
1867c478bd9Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_IF_MASK) ? "IF" : "if",
1877c478bd9Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_TF_MASK) ? "TF" : "tf",
1887c478bd9Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_SF_MASK) ? "SF" : "sf",
1897c478bd9Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_ZF_MASK) ? "ZF" : "zf",
1907c478bd9Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_AF_MASK) ? "AF" : "af",
1917c478bd9Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_PF_MASK) ? "PF" : "pf",
1927c478bd9Sstevel@tonic-gate 	    (rflags & KREG_EFLAGS_CF_MASK) ? "CF" : "cf");
1937c478bd9Sstevel@tonic-gate 
19474ecdb51SJohn Levon 	mdb_printf("%%cs = 0x%04x\t%%ds = 0x%04x\t"
19574ecdb51SJohn Levon 	    "%%es = 0x%04x\t%%fs = 0x%04x\n", kregs[KREG_CS], kregs[KREG_DS],
19674ecdb51SJohn Levon 	    kregs[KREG_ES], kregs[KREG_FS] & 0xffff);
19774ecdb51SJohn Levon 	mdb_printf("%%gs = 0x%04x\t%%gsbase = 0x%lx\t%%kgsbase = 0x%lx\n",
19874ecdb51SJohn Levon 	    kregs[KREG_GS] & 0xffff, kregs[KREG_GSBASE], kregs[KREG_KGSBASE]);
1995f633405SAlex Wilson 	mdb_printf("%%trapno = 0x%x\t%%err = 0x%x\t%%cr2 = 0x%lx\t"
2005f633405SAlex Wilson 	    "%%cr3 = 0x%lx\n", kregs[KREG_TRAPNO], kregs[KREG_ERR],
2015f633405SAlex Wilson 	    kregs[KREG_CR2], kregs[KREG_CR3]);
2027c478bd9Sstevel@tonic-gate }
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate int
mdb_amd64_kvm_stack_iter(mdb_tgt_t * t,const mdb_tgt_gregset_t * gsp,mdb_tgt_stack_f * func,void * arg)2057c478bd9Sstevel@tonic-gate mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
2067c478bd9Sstevel@tonic-gate     mdb_tgt_stack_f *func, void *arg)
2077c478bd9Sstevel@tonic-gate {
2087c478bd9Sstevel@tonic-gate 	mdb_tgt_gregset_t gregs;
2097c478bd9Sstevel@tonic-gate 	kreg_t *kregs = &gregs.kregs[0];
2107c478bd9Sstevel@tonic-gate 	int got_pc = (gsp->kregs[KREG_RIP] != 0);
211159eb9e1Ssherrym 	uint_t argc, reg_argc;
212159eb9e1Ssherrym 	long fr_argv[32];
213159eb9e1Ssherrym 	int start_index; /* index to save_instr where to start comparison */
2140b453801SGordon Ross 	int err;
215159eb9e1Ssherrym 	int i;
2167c478bd9Sstevel@tonic-gate 
21732b5e9f0SRichard Lowe 	struct fr {
2187c478bd9Sstevel@tonic-gate 		uintptr_t fr_savfp;
2197c478bd9Sstevel@tonic-gate 		uintptr_t fr_savpc;
2207c478bd9Sstevel@tonic-gate 	} fr;
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	uintptr_t fp = gsp->kregs[KREG_RBP];
2237c478bd9Sstevel@tonic-gate 	uintptr_t pc = gsp->kregs[KREG_RIP];
2240b453801SGordon Ross 	uintptr_t lastfp = 0;
225159eb9e1Ssherrym 
226159eb9e1Ssherrym 	ssize_t size;
2272d4be7aaSRichard Lowe 	ssize_t insnsize;
2282d4be7aaSRichard Lowe 	uint8_t ins[SAVEARGS_INSN_SEQ_LEN];
229159eb9e1Ssherrym 
230159eb9e1Ssherrym 	GElf_Sym s;
231159eb9e1Ssherrym 	mdb_syminfo_t sip;
232159eb9e1Ssherrym 	mdb_ctf_funcinfo_t mfp;
233843e1988Sjohnlev 	int xpv_panic = 0;
23432b5e9f0SRichard Lowe 	int advance_tortoise = 1;
23532b5e9f0SRichard Lowe 	uintptr_t tortoise_fp = 0;
236843e1988Sjohnlev #ifndef	_KMDB
237843e1988Sjohnlev 	int xp;
238843e1988Sjohnlev 
239843e1988Sjohnlev 	if ((mdb_readsym(&xp, sizeof (xp), "xpv_panicking") != -1) && (xp > 0))
240843e1988Sjohnlev 		xpv_panic = 1;
241843e1988Sjohnlev #endif
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	bcopy(gsp, &gregs, sizeof (gregs));
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	while (fp != 0) {
2462d4be7aaSRichard Lowe 		int args_style = 0;
2477c478bd9Sstevel@tonic-gate 
248*9c3024a3SHans Rosenfeld 		if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S, &fr, sizeof (fr), fp) !=
249*9c3024a3SHans Rosenfeld 		    sizeof (fr)) {
2500b453801SGordon Ross 			err = EMDB_NOMAP;
2510b453801SGordon Ross 			goto badfp;
2520b453801SGordon Ross 		}
253159eb9e1Ssherrym 
25432b5e9f0SRichard Lowe 		if (tortoise_fp == 0) {
25532b5e9f0SRichard Lowe 			tortoise_fp = fp;
25632b5e9f0SRichard Lowe 		} else {
25732b5e9f0SRichard Lowe 			/*
25832b5e9f0SRichard Lowe 			 * Advance tortoise_fp every other frame, so we detect
25932b5e9f0SRichard Lowe 			 * cycles with Floyd's tortoise/hare.
26032b5e9f0SRichard Lowe 			 */
26132b5e9f0SRichard Lowe 			if (advance_tortoise != 0) {
26232b5e9f0SRichard Lowe 				struct fr tfr;
26332b5e9f0SRichard Lowe 
264*9c3024a3SHans Rosenfeld 				if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S, &tfr,
265*9c3024a3SHans Rosenfeld 				    sizeof (tfr), tortoise_fp) !=
266*9c3024a3SHans Rosenfeld 				    sizeof (tfr)) {
26732b5e9f0SRichard Lowe 					err = EMDB_NOMAP;
26832b5e9f0SRichard Lowe 					goto badfp;
26932b5e9f0SRichard Lowe 				}
27032b5e9f0SRichard Lowe 
27132b5e9f0SRichard Lowe 				tortoise_fp = tfr.fr_savfp;
27232b5e9f0SRichard Lowe 			}
27332b5e9f0SRichard Lowe 
27432b5e9f0SRichard Lowe 			if (fp == tortoise_fp) {
27532b5e9f0SRichard Lowe 				err = EMDB_STKFRAME;
27632b5e9f0SRichard Lowe 				goto badfp;
27732b5e9f0SRichard Lowe 			}
27832b5e9f0SRichard Lowe 		}
27932b5e9f0SRichard Lowe 
28032b5e9f0SRichard Lowe 		advance_tortoise = !advance_tortoise;
28132b5e9f0SRichard Lowe 
282159eb9e1Ssherrym 		if ((mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY,
283159eb9e1Ssherrym 		    NULL, 0, &s, &sip) == 0) &&
284159eb9e1Ssherrym 		    (mdb_ctf_func_info(&s, &sip, &mfp) == 0)) {
285159eb9e1Ssherrym 			int return_type = mdb_ctf_type_kind(mfp.mtf_return);
2862d4be7aaSRichard Lowe 			mdb_ctf_id_t args_types[5];
2872d4be7aaSRichard Lowe 
288159eb9e1Ssherrym 			argc = mfp.mtf_argc;
2892d4be7aaSRichard Lowe 
290159eb9e1Ssherrym 			/*
2912d4be7aaSRichard Lowe 			 * If the function returns a structure or union
2922d4be7aaSRichard Lowe 			 * greater than 16 bytes in size %rdi contains the
2932d4be7aaSRichard Lowe 			 * address in which to store the return value rather
2942d4be7aaSRichard Lowe 			 * than for an argument.
295159eb9e1Ssherrym 			 */
2962d4be7aaSRichard Lowe 			if ((return_type == CTF_K_STRUCT ||
2972d4be7aaSRichard Lowe 			    return_type == CTF_K_UNION) &&
2982d4be7aaSRichard Lowe 			    mdb_ctf_type_size(mfp.mtf_return) > 16)
299159eb9e1Ssherrym 				start_index = 1;
300159eb9e1Ssherrym 			else
301159eb9e1Ssherrym 				start_index = 0;
3022d4be7aaSRichard Lowe 
3032d4be7aaSRichard Lowe 			/*
3042d4be7aaSRichard Lowe 			 * If any of the first 5 arguments are a structure
3052d4be7aaSRichard Lowe 			 * less than 16 bytes in size, it will be passed
3062d4be7aaSRichard Lowe 			 * spread across two argument registers, and we will
3072d4be7aaSRichard Lowe 			 * not cope.
3082d4be7aaSRichard Lowe 			 */
3092d4be7aaSRichard Lowe 			if (mdb_ctf_func_args(&mfp, 5, args_types) == CTF_ERR)
3102d4be7aaSRichard Lowe 				argc = 0;
3112d4be7aaSRichard Lowe 
3122d4be7aaSRichard Lowe 			for (i = 0; i < MIN(5, argc); i++) {
3132d4be7aaSRichard Lowe 				int t = mdb_ctf_type_kind(args_types[i]);
3142d4be7aaSRichard Lowe 
3152d4be7aaSRichard Lowe 				if (((t == CTF_K_STRUCT) ||
3162d4be7aaSRichard Lowe 				    (t == CTF_K_UNION)) &&
3172d4be7aaSRichard Lowe 				    mdb_ctf_type_size(args_types[i]) <= 16) {
3182d4be7aaSRichard Lowe 					argc = 0;
3192d4be7aaSRichard Lowe 					break;
3202d4be7aaSRichard Lowe 				}
3212d4be7aaSRichard Lowe 			}
322159eb9e1Ssherrym 		} else {
323159eb9e1Ssherrym 			argc = 0;
324159eb9e1Ssherrym 		}
3257c478bd9Sstevel@tonic-gate 
3262d4be7aaSRichard Lowe 		/*
3272d4be7aaSRichard Lowe 		 * The number of instructions to search for argument saving is
3282d4be7aaSRichard Lowe 		 * limited such that only instructions prior to %pc are
3292d4be7aaSRichard Lowe 		 * considered such that we never read arguments from a
3302d4be7aaSRichard Lowe 		 * function where the saving code has not in fact yet
3312d4be7aaSRichard Lowe 		 * executed.
3322d4be7aaSRichard Lowe 		 */
3332d4be7aaSRichard Lowe 		insnsize = MIN(MIN(s.st_size, SAVEARGS_INSN_SEQ_LEN),
3342d4be7aaSRichard Lowe 		    pc - s.st_value);
3352d4be7aaSRichard Lowe 
336*9c3024a3SHans Rosenfeld 		if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, ins, insnsize,
337*9c3024a3SHans Rosenfeld 		    s.st_value) != insnsize)
3382d4be7aaSRichard Lowe 			argc = 0;
339159eb9e1Ssherrym 
3402d4be7aaSRichard Lowe 		if ((argc != 0) &&
3412d4be7aaSRichard Lowe 		    ((args_style = saveargs_has_args(ins, insnsize, argc,
3422d4be7aaSRichard Lowe 		    start_index)) != SAVEARGS_NO_ARGS)) {
3432d4be7aaSRichard Lowe 			/* Up to 6 arguments are passed via registers */
3442d4be7aaSRichard Lowe 			reg_argc = MIN((6 - start_index), mfp.mtf_argc);
345159eb9e1Ssherrym 			size = reg_argc * sizeof (long);
346159eb9e1Ssherrym 
3472d4be7aaSRichard Lowe 			/*
3482d4be7aaSRichard Lowe 			 * If Studio pushed a structure return address as an
3492d4be7aaSRichard Lowe 			 * argument, we need to read one more argument than
3502d4be7aaSRichard Lowe 			 * actually exists (the addr) to make everything line
3512d4be7aaSRichard Lowe 			 * up.
3522d4be7aaSRichard Lowe 			 */
3532d4be7aaSRichard Lowe 			if (args_style == SAVEARGS_STRUCT_ARGS)
3542d4be7aaSRichard Lowe 				size += sizeof (long);
3552d4be7aaSRichard Lowe 
356*9c3024a3SHans Rosenfeld 			if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S, fr_argv, size,
357*9c3024a3SHans Rosenfeld 			    (fp - size)) != size)
358159eb9e1Ssherrym 				return (-1);	/* errno has been set for us */
359159eb9e1Ssherrym 
360159eb9e1Ssherrym 			/*
361159eb9e1Ssherrym 			 * Arrange the arguments in the right order for
362159eb9e1Ssherrym 			 * printing.
363159eb9e1Ssherrym 			 */
3642d4be7aaSRichard Lowe 			for (i = 0; i < (reg_argc / 2); i++) {
365159eb9e1Ssherrym 				long t = fr_argv[i];
366159eb9e1Ssherrym 
367159eb9e1Ssherrym 				fr_argv[i] = fr_argv[reg_argc - i - 1];
368159eb9e1Ssherrym 				fr_argv[reg_argc - i - 1] = t;
369159eb9e1Ssherrym 			}
370159eb9e1Ssherrym 
3712d4be7aaSRichard Lowe 			if (argc > reg_argc) {
3722d4be7aaSRichard Lowe 				size = MIN((argc - reg_argc) * sizeof (long),
3732d4be7aaSRichard Lowe 				    sizeof (fr_argv) -
3742d4be7aaSRichard Lowe 				    (reg_argc * sizeof (long)));
3752d4be7aaSRichard Lowe 
376*9c3024a3SHans Rosenfeld 				if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S,
377*9c3024a3SHans Rosenfeld 				    &fr_argv[reg_argc], size,
378159eb9e1Ssherrym 				    fp + sizeof (fr)) != size)
379159eb9e1Ssherrym 					return (-1); /* errno has been set */
380159eb9e1Ssherrym 			}
3812d4be7aaSRichard Lowe 		} else {
382159eb9e1Ssherrym 			argc = 0;
3832d4be7aaSRichard Lowe 		}
384159eb9e1Ssherrym 
385159eb9e1Ssherrym 		if (got_pc && func(arg, pc, argc, fr_argv, &gregs) != 0)
3867c478bd9Sstevel@tonic-gate 			break;
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 		kregs[KREG_RSP] = kregs[KREG_RBP];
3897c478bd9Sstevel@tonic-gate 
390843e1988Sjohnlev 		lastfp = fp;
391843e1988Sjohnlev 		fp = fr.fr_savfp;
392843e1988Sjohnlev 		/*
393843e1988Sjohnlev 		 * The Xen hypervisor marks a stack frame as belonging to
394843e1988Sjohnlev 		 * an exception by inverting the bits of the pointer to
395843e1988Sjohnlev 		 * that frame.  We attempt to identify these frames by
396843e1988Sjohnlev 		 * inverting the pointer and seeing if it is within 0xfff
397843e1988Sjohnlev 		 * bytes of the last frame.
398843e1988Sjohnlev 		 */
399843e1988Sjohnlev 		if (xpv_panic)
400843e1988Sjohnlev 			if ((fp != 0) && (fp < lastfp) &&
401843e1988Sjohnlev 			    ((lastfp ^ ~fp) < 0xfff))
40221072fc3SMarcel Telka 				fp = ~fp;
403843e1988Sjohnlev 
404843e1988Sjohnlev 		kregs[KREG_RBP] = fp;
4057c478bd9Sstevel@tonic-gate 		kregs[KREG_RIP] = pc = fr.fr_savpc;
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 		got_pc = (pc != 0);
4087c478bd9Sstevel@tonic-gate 	}
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	return (0);
4110b453801SGordon Ross 
4120b453801SGordon Ross badfp:
4130b453801SGordon Ross 	mdb_printf("%p [%s]", fp, mdb_strerror(err));
4140b453801SGordon Ross 	return (set_errno(err));
4157c478bd9Sstevel@tonic-gate }
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate /*
4187c478bd9Sstevel@tonic-gate  * Determine the return address for the current frame.  Typically this is the
4197c478bd9Sstevel@tonic-gate  * fr_savpc value from the current frame, but we also perform some special
4207c478bd9Sstevel@tonic-gate  * handling to see if we are stopped on one of the first two instructions of
4217c478bd9Sstevel@tonic-gate  * a typical function prologue, in which case %rbp will not be set up yet.
4227c478bd9Sstevel@tonic-gate  */
4237c478bd9Sstevel@tonic-gate int
mdb_amd64_step_out(mdb_tgt_t * t,uintptr_t * p,kreg_t pc,kreg_t fp,kreg_t sp,mdb_instr_t curinstr)4247c478bd9Sstevel@tonic-gate mdb_amd64_step_out(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, kreg_t fp, kreg_t sp,
4257c478bd9Sstevel@tonic-gate     mdb_instr_t curinstr)
4267c478bd9Sstevel@tonic-gate {
4277c478bd9Sstevel@tonic-gate 	struct frame fr;
4287c478bd9Sstevel@tonic-gate 	GElf_Sym s;
4297c478bd9Sstevel@tonic-gate 	char buf[1];
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	enum {
4327c478bd9Sstevel@tonic-gate 		M_PUSHQ_RBP	= 0x55,	/* pushq %rbp */
4337c478bd9Sstevel@tonic-gate 		M_REX_W		= 0x48, /* REX prefix with only W set */
4347c478bd9Sstevel@tonic-gate 		M_MOVL_RBP	= 0x8b	/* movq %rsp, %rbp with prefix */
4357c478bd9Sstevel@tonic-gate 	};
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	if (mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY,
4387c478bd9Sstevel@tonic-gate 	    buf, 0, &s, NULL) == 0) {
4397c478bd9Sstevel@tonic-gate 		if (pc == s.st_value && curinstr == M_PUSHQ_RBP)
4407c478bd9Sstevel@tonic-gate 			fp = sp - 8;
4417c478bd9Sstevel@tonic-gate 		else if (pc == s.st_value + 1 && curinstr == M_REX_W) {
442*9c3024a3SHans Rosenfeld 			if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, &curinstr,
443*9c3024a3SHans Rosenfeld 			    sizeof (curinstr), pc + 1) == sizeof (curinstr) &&
444*9c3024a3SHans Rosenfeld 			    curinstr == M_MOVL_RBP)
4457c478bd9Sstevel@tonic-gate 				fp = sp;
4467c478bd9Sstevel@tonic-gate 		}
4477c478bd9Sstevel@tonic-gate 	}
4487c478bd9Sstevel@tonic-gate 
449*9c3024a3SHans Rosenfeld 	if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_S, &fr, sizeof (fr), fp) ==
450*9c3024a3SHans Rosenfeld 	    sizeof (fr)) {
4517c478bd9Sstevel@tonic-gate 		*p = fr.fr_savpc;
4527c478bd9Sstevel@tonic-gate 		return (0);
4537c478bd9Sstevel@tonic-gate 	}
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	return (-1); /* errno is set for us */
4567c478bd9Sstevel@tonic-gate }
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4597c478bd9Sstevel@tonic-gate int
mdb_amd64_next(mdb_tgt_t * t,uintptr_t * p,kreg_t pc,mdb_instr_t curinstr)4607c478bd9Sstevel@tonic-gate mdb_amd64_next(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, mdb_instr_t curinstr)
4617c478bd9Sstevel@tonic-gate {
4627c478bd9Sstevel@tonic-gate 	mdb_tgt_addr_t npc;
463b2c0fa2eSdmick 	mdb_tgt_addr_t callpc;
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	enum {
4667c478bd9Sstevel@tonic-gate 		M_CALL_REL = 0xe8, /* call near with relative displacement */
4677c478bd9Sstevel@tonic-gate 		M_CALL_REG = 0xff, /* call near indirect or call far register */
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 		M_REX_LO = 0x40,
4707c478bd9Sstevel@tonic-gate 		M_REX_HI = 0x4f
4717c478bd9Sstevel@tonic-gate 	};
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	/*
4747c478bd9Sstevel@tonic-gate 	 * If the opcode is a near call with relative displacement, assume the
4757c478bd9Sstevel@tonic-gate 	 * displacement is a rel32 from the next instruction.
4767c478bd9Sstevel@tonic-gate 	 */
4777c478bd9Sstevel@tonic-gate 	if (curinstr == M_CALL_REL) {
4787c478bd9Sstevel@tonic-gate 		*p = pc + sizeof (mdb_instr_t) + sizeof (uint32_t);
4797c478bd9Sstevel@tonic-gate 		return (0);
4807c478bd9Sstevel@tonic-gate 	}
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	/* Skip the rex prefix, if any */
483b2c0fa2eSdmick 	callpc = pc;
484b2c0fa2eSdmick 	while (curinstr >= M_REX_LO && curinstr <= M_REX_HI) {
485*9c3024a3SHans Rosenfeld 		if (mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, &curinstr,
486*9c3024a3SHans Rosenfeld 		    sizeof (curinstr), ++callpc) != sizeof (curinstr))
487b2c0fa2eSdmick 			return (-1); /* errno is set for us */
488b2c0fa2eSdmick 	}
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	if (curinstr != M_CALL_REG) {
4917c478bd9Sstevel@tonic-gate 		/* It's not a call */
4927c478bd9Sstevel@tonic-gate 		return (set_errno(EAGAIN));
4937c478bd9Sstevel@tonic-gate 	}
4947c478bd9Sstevel@tonic-gate 
495*9c3024a3SHans Rosenfeld 	npc = mdb_dis_nextins(mdb.m_disasm, t, MDB_TGT_AS_VIRT_I, pc);
496*9c3024a3SHans Rosenfeld 	if (npc == pc)
4977c478bd9Sstevel@tonic-gate 		return (-1); /* errno is set for us */
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	*p = npc;
5007c478bd9Sstevel@tonic-gate 	return (0);
5017c478bd9Sstevel@tonic-gate }
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5047c478bd9Sstevel@tonic-gate int
mdb_amd64_kvm_frame(void * arglim,uintptr_t pc,uint_t argc,const long * argv,const mdb_tgt_gregset_t * gregs)5057c478bd9Sstevel@tonic-gate mdb_amd64_kvm_frame(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
5067c478bd9Sstevel@tonic-gate     const mdb_tgt_gregset_t *gregs)
5077c478bd9Sstevel@tonic-gate {
5087c478bd9Sstevel@tonic-gate 	argc = MIN(argc, (uintptr_t)arglim);
5097c478bd9Sstevel@tonic-gate 	mdb_printf("%a(", pc);
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	if (argc != 0) {
5127c478bd9Sstevel@tonic-gate 		mdb_printf("%lr", *argv++);
5137c478bd9Sstevel@tonic-gate 		for (argc--; argc != 0; argc--)
5147c478bd9Sstevel@tonic-gate 			mdb_printf(", %lr", *argv++);
5157c478bd9Sstevel@tonic-gate 	}
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	mdb_printf(")\n");
5187c478bd9Sstevel@tonic-gate 	return (0);
5197c478bd9Sstevel@tonic-gate }
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate int
mdb_amd64_kvm_framev(void * arglim,uintptr_t pc,uint_t argc,const long * argv,const mdb_tgt_gregset_t * gregs)5227c478bd9Sstevel@tonic-gate mdb_amd64_kvm_framev(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
5237c478bd9Sstevel@tonic-gate     const mdb_tgt_gregset_t *gregs)
5247c478bd9Sstevel@tonic-gate {
525159eb9e1Ssherrym 	/*
526159eb9e1Ssherrym 	 * Historically adb limited stack trace argument display to a fixed-
527159eb9e1Ssherrym 	 * size number of arguments since no symbolic debugging info existed.
528159eb9e1Ssherrym 	 * On amd64 we can detect the true number of saved arguments so only
529159eb9e1Ssherrym 	 * respect an arglim of zero; otherwise display the entire argv[].
530159eb9e1Ssherrym 	 */
531159eb9e1Ssherrym 	if (arglim == 0)
532159eb9e1Ssherrym 		argc = 0;
533159eb9e1Ssherrym 
5347c478bd9Sstevel@tonic-gate 	mdb_printf("%0?lr %a(", gregs->kregs[KREG_RBP], pc);
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	if (argc != 0) {
5377c478bd9Sstevel@tonic-gate 		mdb_printf("%lr", *argv++);
5387c478bd9Sstevel@tonic-gate 		for (argc--; argc != 0; argc--)
5397c478bd9Sstevel@tonic-gate 			mdb_printf(", %lr", *argv++);
5407c478bd9Sstevel@tonic-gate 	}
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate 	mdb_printf(")\n");
5437c478bd9Sstevel@tonic-gate 	return (0);
5447c478bd9Sstevel@tonic-gate }
545