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 /*
270a47c91cSRobert Mustacchi * Copyright (c) 2012, Joyent, Inc. All rights reserved.
2854a796dfSGordon Ross * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
29c9aaf1c2SAdam 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>
427c478bd9Sstevel@tonic-gate #include <mdb/mdb_amd64util.h>
43159eb9e1Ssherrym #include <mdb/mdb_ctf.h>
447c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h>
457c478bd9Sstevel@tonic-gate #include <mdb/mdb.h>
467c478bd9Sstevel@tonic-gate
472d4be7aaSRichard Lowe #include <saveargs.h>
482d4be7aaSRichard Lowe
497c478bd9Sstevel@tonic-gate /*
507c478bd9Sstevel@tonic-gate * This array is used by the getareg and putareg entry points, and also by our
517c478bd9Sstevel@tonic-gate * register variable discipline.
527c478bd9Sstevel@tonic-gate */
537c478bd9Sstevel@tonic-gate
547c478bd9Sstevel@tonic-gate const mdb_tgt_regdesc_t mdb_amd64_kregs[] = {
557c478bd9Sstevel@tonic-gate { "savfp", KREG_SAVFP, MDB_TGT_R_EXPORT },
567c478bd9Sstevel@tonic-gate { "savpc", KREG_SAVPC, MDB_TGT_R_EXPORT },
577c478bd9Sstevel@tonic-gate { "rdi", KREG_RDI, MDB_TGT_R_EXPORT },
580a47c91cSRobert Mustacchi { "edi", KREG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
590a47c91cSRobert Mustacchi { "di", KREG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
600a47c91cSRobert Mustacchi { "dil", KREG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
617c478bd9Sstevel@tonic-gate { "rsi", KREG_RSI, MDB_TGT_R_EXPORT },
620a47c91cSRobert Mustacchi { "esi", KREG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
630a47c91cSRobert Mustacchi { "si", KREG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
640a47c91cSRobert Mustacchi { "sil", KREG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
657c478bd9Sstevel@tonic-gate { "rdx", KREG_RDX, MDB_TGT_R_EXPORT },
660a47c91cSRobert Mustacchi { "edx", KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
670a47c91cSRobert Mustacchi { "dx", KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
680a47c91cSRobert Mustacchi { "dh", KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
690a47c91cSRobert Mustacchi { "dl", KREG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
707c478bd9Sstevel@tonic-gate { "rcx", KREG_RCX, MDB_TGT_R_EXPORT },
710a47c91cSRobert Mustacchi { "ecx", KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
720a47c91cSRobert Mustacchi { "cx", KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
730a47c91cSRobert Mustacchi { "ch", KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
740a47c91cSRobert Mustacchi { "cl", KREG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
757c478bd9Sstevel@tonic-gate { "r8", KREG_R8, MDB_TGT_R_EXPORT },
760a47c91cSRobert Mustacchi { "r8d", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
770a47c91cSRobert Mustacchi { "r8w", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
780a47c91cSRobert Mustacchi { "r8l", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
797c478bd9Sstevel@tonic-gate { "r9", KREG_R9, MDB_TGT_R_EXPORT },
800a47c91cSRobert Mustacchi { "r9d", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
810a47c91cSRobert Mustacchi { "r9w", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
820a47c91cSRobert Mustacchi { "r9l", KREG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
837c478bd9Sstevel@tonic-gate { "rax", KREG_RAX, MDB_TGT_R_EXPORT },
840a47c91cSRobert Mustacchi { "eax", KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
850a47c91cSRobert Mustacchi { "ax", KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
860a47c91cSRobert Mustacchi { "ah", KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
870a47c91cSRobert Mustacchi { "al", KREG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
887c478bd9Sstevel@tonic-gate { "rbx", KREG_RBX, MDB_TGT_R_EXPORT },
890a47c91cSRobert Mustacchi { "ebx", KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
900a47c91cSRobert Mustacchi { "bx", KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
910a47c91cSRobert Mustacchi { "bh", KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H },
920a47c91cSRobert Mustacchi { "bl", KREG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
937c478bd9Sstevel@tonic-gate { "rbp", KREG_RBP, MDB_TGT_R_EXPORT },
940a47c91cSRobert Mustacchi { "ebp", KREG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
950a47c91cSRobert Mustacchi { "bp", KREG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
960a47c91cSRobert Mustacchi { "bpl", KREG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
977c478bd9Sstevel@tonic-gate { "r10", KREG_R10, MDB_TGT_R_EXPORT },
980a47c91cSRobert Mustacchi { "r10d", KREG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
990a47c91cSRobert Mustacchi { "r10w", KREG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
1000a47c91cSRobert Mustacchi { "r10l", KREG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
1017c478bd9Sstevel@tonic-gate { "r11", KREG_R11, MDB_TGT_R_EXPORT },
1020a47c91cSRobert Mustacchi { "r11d", KREG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
1030a47c91cSRobert Mustacchi { "r11w", KREG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
1040a47c91cSRobert Mustacchi { "r11l", KREG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
1057c478bd9Sstevel@tonic-gate { "r12", KREG_R12, MDB_TGT_R_EXPORT },
1060a47c91cSRobert Mustacchi { "r12d", KREG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
1070a47c91cSRobert Mustacchi { "r12w", KREG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
1080a47c91cSRobert Mustacchi { "r12l", KREG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
1097c478bd9Sstevel@tonic-gate { "r13", KREG_R13, MDB_TGT_R_EXPORT },
1100a47c91cSRobert Mustacchi { "r13d", KREG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
1110a47c91cSRobert Mustacchi { "r13w", KREG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
1120a47c91cSRobert Mustacchi { "r13l", KREG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
1137c478bd9Sstevel@tonic-gate { "r14", KREG_R14, MDB_TGT_R_EXPORT },
1140a47c91cSRobert Mustacchi { "r14d", KREG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
1150a47c91cSRobert Mustacchi { "r14w", KREG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
1160a47c91cSRobert Mustacchi { "r14l", KREG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
1177c478bd9Sstevel@tonic-gate { "r15", KREG_R15, MDB_TGT_R_EXPORT },
1180a47c91cSRobert Mustacchi { "r15d", KREG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
1190a47c91cSRobert Mustacchi { "r15w", KREG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
1200a47c91cSRobert Mustacchi { "r15l", KREG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
1217c478bd9Sstevel@tonic-gate { "ds", KREG_DS, MDB_TGT_R_EXPORT },
1227c478bd9Sstevel@tonic-gate { "es", KREG_ES, MDB_TGT_R_EXPORT },
1237c478bd9Sstevel@tonic-gate { "fs", KREG_FS, MDB_TGT_R_EXPORT },
1247c478bd9Sstevel@tonic-gate { "gs", KREG_GS, MDB_TGT_R_EXPORT },
1257c478bd9Sstevel@tonic-gate { "trapno", KREG_TRAPNO, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
1267c478bd9Sstevel@tonic-gate { "err", KREG_ERR, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV },
1277c478bd9Sstevel@tonic-gate { "rip", KREG_RIP, MDB_TGT_R_EXPORT },
1287c478bd9Sstevel@tonic-gate { "cs", KREG_CS, MDB_TGT_R_EXPORT },
1297c478bd9Sstevel@tonic-gate { "rflags", KREG_RFLAGS, MDB_TGT_R_EXPORT },
1300a47c91cSRobert Mustacchi { "eflags", KREG_RFLAGS, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
1317c478bd9Sstevel@tonic-gate { "rsp", KREG_RSP, MDB_TGT_R_EXPORT },
1320a47c91cSRobert Mustacchi { "esp", KREG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_32 },
1330a47c91cSRobert Mustacchi { "sp", KREG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 },
1340a47c91cSRobert Mustacchi { "spl", KREG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_8L },
1357c478bd9Sstevel@tonic-gate { "ss", KREG_SS, MDB_TGT_R_EXPORT },
1367c478bd9Sstevel@tonic-gate { NULL, 0, 0 }
1377c478bd9Sstevel@tonic-gate };
1387c478bd9Sstevel@tonic-gate
1397c478bd9Sstevel@tonic-gate void
mdb_amd64_printregs(const mdb_tgt_gregset_t * gregs)1407c478bd9Sstevel@tonic-gate mdb_amd64_printregs(const mdb_tgt_gregset_t *gregs)
1417c478bd9Sstevel@tonic-gate {
1427c478bd9Sstevel@tonic-gate const kreg_t *kregs = &gregs->kregs[0];
1437c478bd9Sstevel@tonic-gate kreg_t rflags = kregs[KREG_RFLAGS];
1447c478bd9Sstevel@tonic-gate
1457c478bd9Sstevel@tonic-gate #define GETREG2(x) ((uintptr_t)kregs[(x)]), ((uintptr_t)kregs[(x)])
1467c478bd9Sstevel@tonic-gate
1477c478bd9Sstevel@tonic-gate mdb_printf("%%rax = 0x%0?p %15A %%r9 = 0x%0?p %A\n",
1487c478bd9Sstevel@tonic-gate GETREG2(KREG_RAX), GETREG2(KREG_R9));
1497c478bd9Sstevel@tonic-gate mdb_printf("%%rbx = 0x%0?p %15A %%r10 = 0x%0?p %A\n",
1507c478bd9Sstevel@tonic-gate GETREG2(KREG_RBX), GETREG2(KREG_R10));
1517c478bd9Sstevel@tonic-gate mdb_printf("%%rcx = 0x%0?p %15A %%r11 = 0x%0?p %A\n",
1527c478bd9Sstevel@tonic-gate GETREG2(KREG_RCX), GETREG2(KREG_R11));
1537c478bd9Sstevel@tonic-gate mdb_printf("%%rdx = 0x%0?p %15A %%r12 = 0x%0?p %A\n",
1547c478bd9Sstevel@tonic-gate GETREG2(KREG_RDX), GETREG2(KREG_R12));
1557c478bd9Sstevel@tonic-gate mdb_printf("%%rsi = 0x%0?p %15A %%r13 = 0x%0?p %A\n",
1567c478bd9Sstevel@tonic-gate GETREG2(KREG_RSI), GETREG2(KREG_R13));
1577c478bd9Sstevel@tonic-gate mdb_printf("%%rdi = 0x%0?p %15A %%r14 = 0x%0?p %A\n",
1587c478bd9Sstevel@tonic-gate GETREG2(KREG_RDI), GETREG2(KREG_R14));
1597c478bd9Sstevel@tonic-gate mdb_printf("%%r8 = 0x%0?p %15A %%r15 = 0x%0?p %A\n\n",
1607c478bd9Sstevel@tonic-gate GETREG2(KREG_R8), GETREG2(KREG_R15));
1617c478bd9Sstevel@tonic-gate
1627c478bd9Sstevel@tonic-gate mdb_printf("%%rip = 0x%0?p %A\n", GETREG2(KREG_RIP));
1637c478bd9Sstevel@tonic-gate mdb_printf("%%rbp = 0x%0?p\n", kregs[KREG_RBP]);
1647c478bd9Sstevel@tonic-gate mdb_printf("%%rsp = 0x%0?p\n", kregs[KREG_RSP]);
1657c478bd9Sstevel@tonic-gate
1667c478bd9Sstevel@tonic-gate mdb_printf("%%rflags = 0x%08x\n", rflags);
1677c478bd9Sstevel@tonic-gate
1687c478bd9Sstevel@tonic-gate mdb_printf(" id=%u vip=%u vif=%u ac=%u vm=%u rf=%u nt=%u iopl=0x%x\n",
1697c478bd9Sstevel@tonic-gate (rflags & KREG_EFLAGS_ID_MASK) >> KREG_EFLAGS_ID_SHIFT,
1707c478bd9Sstevel@tonic-gate (rflags & KREG_EFLAGS_VIP_MASK) >> KREG_EFLAGS_VIP_SHIFT,
1717c478bd9Sstevel@tonic-gate (rflags & KREG_EFLAGS_VIF_MASK) >> KREG_EFLAGS_VIF_SHIFT,
1727c478bd9Sstevel@tonic-gate (rflags & KREG_EFLAGS_AC_MASK) >> KREG_EFLAGS_AC_SHIFT,
1737c478bd9Sstevel@tonic-gate (rflags & KREG_EFLAGS_VM_MASK) >> KREG_EFLAGS_VM_SHIFT,
1747c478bd9Sstevel@tonic-gate (rflags & KREG_EFLAGS_RF_MASK) >> KREG_EFLAGS_RF_SHIFT,
1757c478bd9Sstevel@tonic-gate (rflags & KREG_EFLAGS_NT_MASK) >> KREG_EFLAGS_NT_SHIFT,
1767c478bd9Sstevel@tonic-gate (rflags & KREG_EFLAGS_IOPL_MASK) >> KREG_EFLAGS_IOPL_SHIFT);
1777c478bd9Sstevel@tonic-gate
1787c478bd9Sstevel@tonic-gate mdb_printf(" status=<%s,%s,%s,%s,%s,%s,%s,%s,%s>\n\n",
1797c478bd9Sstevel@tonic-gate (rflags & KREG_EFLAGS_OF_MASK) ? "OF" : "of",
1807c478bd9Sstevel@tonic-gate (rflags & KREG_EFLAGS_DF_MASK) ? "DF" : "df",
1817c478bd9Sstevel@tonic-gate (rflags & KREG_EFLAGS_IF_MASK) ? "IF" : "if",
1827c478bd9Sstevel@tonic-gate (rflags & KREG_EFLAGS_TF_MASK) ? "TF" : "tf",
1837c478bd9Sstevel@tonic-gate (rflags & KREG_EFLAGS_SF_MASK) ? "SF" : "sf",
1847c478bd9Sstevel@tonic-gate (rflags & KREG_EFLAGS_ZF_MASK) ? "ZF" : "zf",
1857c478bd9Sstevel@tonic-gate (rflags & KREG_EFLAGS_AF_MASK) ? "AF" : "af",
1867c478bd9Sstevel@tonic-gate (rflags & KREG_EFLAGS_PF_MASK) ? "PF" : "pf",
1877c478bd9Sstevel@tonic-gate (rflags & KREG_EFLAGS_CF_MASK) ? "CF" : "cf");
1887c478bd9Sstevel@tonic-gate
1897c478bd9Sstevel@tonic-gate mdb_printf("%24s%%cs = 0x%04x\t%%ds = 0x%04x\t%%es = 0x%04x\n",
1907c478bd9Sstevel@tonic-gate " ", kregs[KREG_CS], kregs[KREG_DS], kregs[KREG_ES]);
1917c478bd9Sstevel@tonic-gate
192ae115bc7Smrj mdb_printf("%%trapno = 0x%x\t\t%%fs = 0x%04x\t%%gs = 0x%04x\n",
193ae115bc7Smrj kregs[KREG_TRAPNO], (kregs[KREG_FS] & 0xffff),
194ae115bc7Smrj (kregs[KREG_GS] & 0xffff));
195ae115bc7Smrj mdb_printf(" %%err = 0x%x\n", kregs[KREG_ERR]);
1967c478bd9Sstevel@tonic-gate }
1977c478bd9Sstevel@tonic-gate
1987c478bd9Sstevel@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)1997c478bd9Sstevel@tonic-gate mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp,
2007c478bd9Sstevel@tonic-gate mdb_tgt_stack_f *func, void *arg)
2017c478bd9Sstevel@tonic-gate {
2027c478bd9Sstevel@tonic-gate mdb_tgt_gregset_t gregs;
2037c478bd9Sstevel@tonic-gate kreg_t *kregs = &gregs.kregs[0];
2047c478bd9Sstevel@tonic-gate int got_pc = (gsp->kregs[KREG_RIP] != 0);
205159eb9e1Ssherrym uint_t argc, reg_argc;
206159eb9e1Ssherrym long fr_argv[32];
207159eb9e1Ssherrym int start_index; /* index to save_instr where to start comparison */
20854a796dfSGordon Ross int err;
209159eb9e1Ssherrym int i;
2107c478bd9Sstevel@tonic-gate
211*c6be10f6SRichard Lowe struct fr {
2127c478bd9Sstevel@tonic-gate uintptr_t fr_savfp;
2137c478bd9Sstevel@tonic-gate uintptr_t fr_savpc;
2147c478bd9Sstevel@tonic-gate } fr;
2157c478bd9Sstevel@tonic-gate
2167c478bd9Sstevel@tonic-gate uintptr_t fp = gsp->kregs[KREG_RBP];
2177c478bd9Sstevel@tonic-gate uintptr_t pc = gsp->kregs[KREG_RIP];
21854a796dfSGordon Ross uintptr_t lastfp = 0;
219159eb9e1Ssherrym
220159eb9e1Ssherrym ssize_t size;
2212d4be7aaSRichard Lowe ssize_t insnsize;
2222d4be7aaSRichard Lowe uint8_t ins[SAVEARGS_INSN_SEQ_LEN];
223159eb9e1Ssherrym
224159eb9e1Ssherrym GElf_Sym s;
225159eb9e1Ssherrym mdb_syminfo_t sip;
226159eb9e1Ssherrym mdb_ctf_funcinfo_t mfp;
227843e1988Sjohnlev int xpv_panic = 0;
228*c6be10f6SRichard Lowe int advance_tortoise = 1;
229*c6be10f6SRichard Lowe uintptr_t tortoise_fp = 0;
230843e1988Sjohnlev #ifndef _KMDB
231843e1988Sjohnlev int xp;
232843e1988Sjohnlev
233843e1988Sjohnlev if ((mdb_readsym(&xp, sizeof (xp), "xpv_panicking") != -1) && (xp > 0))
234843e1988Sjohnlev xpv_panic = 1;
235843e1988Sjohnlev #endif
2367c478bd9Sstevel@tonic-gate
2377c478bd9Sstevel@tonic-gate bcopy(gsp, &gregs, sizeof (gregs));
2387c478bd9Sstevel@tonic-gate
2397c478bd9Sstevel@tonic-gate while (fp != 0) {
2402d4be7aaSRichard Lowe int args_style = 0;
2417c478bd9Sstevel@tonic-gate
24254a796dfSGordon Ross if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) != sizeof (fr)) {
24354a796dfSGordon Ross err = EMDB_NOMAP;
24454a796dfSGordon Ross goto badfp;
24554a796dfSGordon Ross }
2467c478bd9Sstevel@tonic-gate
247*c6be10f6SRichard Lowe if (tortoise_fp == 0) {
248*c6be10f6SRichard Lowe tortoise_fp = fp;
249*c6be10f6SRichard Lowe } else {
250*c6be10f6SRichard Lowe /*
251*c6be10f6SRichard Lowe * Advance tortoise_fp every other frame, so we detect
252*c6be10f6SRichard Lowe * cycles with Floyd's tortoise/hare.
253*c6be10f6SRichard Lowe */
254*c6be10f6SRichard Lowe if (advance_tortoise != 0) {
255*c6be10f6SRichard Lowe struct fr tfr;
256*c6be10f6SRichard Lowe
257*c6be10f6SRichard Lowe if (mdb_tgt_vread(t, &tfr, sizeof (tfr),
258*c6be10f6SRichard Lowe tortoise_fp) != sizeof (tfr)) {
259*c6be10f6SRichard Lowe err = EMDB_NOMAP;
260*c6be10f6SRichard Lowe goto badfp;
261*c6be10f6SRichard Lowe }
262*c6be10f6SRichard Lowe
263*c6be10f6SRichard Lowe tortoise_fp = tfr.fr_savfp;
264*c6be10f6SRichard Lowe }
265*c6be10f6SRichard Lowe
266*c6be10f6SRichard Lowe if (fp == tortoise_fp) {
267*c6be10f6SRichard Lowe err = EMDB_STKFRAME;
268*c6be10f6SRichard Lowe goto badfp;
269*c6be10f6SRichard Lowe }
270*c6be10f6SRichard Lowe }
271*c6be10f6SRichard Lowe
272*c6be10f6SRichard Lowe advance_tortoise = !advance_tortoise;
273*c6be10f6SRichard Lowe
274159eb9e1Ssherrym if ((mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY,
275159eb9e1Ssherrym NULL, 0, &s, &sip) == 0) &&
276159eb9e1Ssherrym (mdb_ctf_func_info(&s, &sip, &mfp) == 0)) {
277159eb9e1Ssherrym int return_type = mdb_ctf_type_kind(mfp.mtf_return);
2782d4be7aaSRichard Lowe mdb_ctf_id_t args_types[5];
2792d4be7aaSRichard Lowe
280159eb9e1Ssherrym argc = mfp.mtf_argc;
2812d4be7aaSRichard Lowe
282159eb9e1Ssherrym /*
2832d4be7aaSRichard Lowe * If the function returns a structure or union
2842d4be7aaSRichard Lowe * greater than 16 bytes in size %rdi contains the
2852d4be7aaSRichard Lowe * address in which to store the return value rather
2862d4be7aaSRichard Lowe * than for an argument.
287159eb9e1Ssherrym */
2882d4be7aaSRichard Lowe if ((return_type == CTF_K_STRUCT ||
2892d4be7aaSRichard Lowe return_type == CTF_K_UNION) &&
2902d4be7aaSRichard Lowe mdb_ctf_type_size(mfp.mtf_return) > 16)
291159eb9e1Ssherrym start_index = 1;
292159eb9e1Ssherrym else
293159eb9e1Ssherrym start_index = 0;
2942d4be7aaSRichard Lowe
2952d4be7aaSRichard Lowe /*
2962d4be7aaSRichard Lowe * If any of the first 5 arguments are a structure
2972d4be7aaSRichard Lowe * less than 16 bytes in size, it will be passed
2982d4be7aaSRichard Lowe * spread across two argument registers, and we will
2992d4be7aaSRichard Lowe * not cope.
3002d4be7aaSRichard Lowe */
3012d4be7aaSRichard Lowe if (mdb_ctf_func_args(&mfp, 5, args_types) == CTF_ERR)
3022d4be7aaSRichard Lowe argc = 0;
3032d4be7aaSRichard Lowe
3042d4be7aaSRichard Lowe for (i = 0; i < MIN(5, argc); i++) {
3052d4be7aaSRichard Lowe int t = mdb_ctf_type_kind(args_types[i]);
3062d4be7aaSRichard Lowe
3072d4be7aaSRichard Lowe if (((t == CTF_K_STRUCT) ||
3082d4be7aaSRichard Lowe (t == CTF_K_UNION)) &&
3092d4be7aaSRichard Lowe mdb_ctf_type_size(args_types[i]) <= 16) {
3102d4be7aaSRichard Lowe argc = 0;
3112d4be7aaSRichard Lowe break;
3122d4be7aaSRichard Lowe }
3132d4be7aaSRichard Lowe }
314159eb9e1Ssherrym } else {
315159eb9e1Ssherrym argc = 0;
316159eb9e1Ssherrym }
317159eb9e1Ssherrym
3182d4be7aaSRichard Lowe /*
3192d4be7aaSRichard Lowe * The number of instructions to search for argument saving is
3202d4be7aaSRichard Lowe * limited such that only instructions prior to %pc are
3212d4be7aaSRichard Lowe * considered such that we never read arguments from a
3222d4be7aaSRichard Lowe * function where the saving code has not in fact yet
3232d4be7aaSRichard Lowe * executed.
3242d4be7aaSRichard Lowe */
3252d4be7aaSRichard Lowe insnsize = MIN(MIN(s.st_size, SAVEARGS_INSN_SEQ_LEN),
3262d4be7aaSRichard Lowe pc - s.st_value);
327159eb9e1Ssherrym
3282d4be7aaSRichard Lowe if (mdb_tgt_vread(t, ins, insnsize, s.st_value) != insnsize)
3292d4be7aaSRichard Lowe argc = 0;
3302d4be7aaSRichard Lowe
3312d4be7aaSRichard Lowe if ((argc != 0) &&
3322d4be7aaSRichard Lowe ((args_style = saveargs_has_args(ins, insnsize, argc,
3332d4be7aaSRichard Lowe start_index)) != SAVEARGS_NO_ARGS)) {
3342d4be7aaSRichard Lowe /* Up to 6 arguments are passed via registers */
3352d4be7aaSRichard Lowe reg_argc = MIN((6 - start_index), mfp.mtf_argc);
336159eb9e1Ssherrym size = reg_argc * sizeof (long);
337159eb9e1Ssherrym
3382d4be7aaSRichard Lowe /*
3392d4be7aaSRichard Lowe * If Studio pushed a structure return address as an
3402d4be7aaSRichard Lowe * argument, we need to read one more argument than
3412d4be7aaSRichard Lowe * actually exists (the addr) to make everything line
3422d4be7aaSRichard Lowe * up.
3432d4be7aaSRichard Lowe */
3442d4be7aaSRichard Lowe if (args_style == SAVEARGS_STRUCT_ARGS)
3452d4be7aaSRichard Lowe size += sizeof (long);
3462d4be7aaSRichard Lowe
347159eb9e1Ssherrym if (mdb_tgt_vread(t, fr_argv, size, (fp - size))
348159eb9e1Ssherrym != size)
349159eb9e1Ssherrym return (-1); /* errno has been set for us */
350159eb9e1Ssherrym
351159eb9e1Ssherrym /*
352159eb9e1Ssherrym * Arrange the arguments in the right order for
353159eb9e1Ssherrym * printing.
354159eb9e1Ssherrym */
3552d4be7aaSRichard Lowe for (i = 0; i < (reg_argc / 2); i++) {
356159eb9e1Ssherrym long t = fr_argv[i];
357159eb9e1Ssherrym
358159eb9e1Ssherrym fr_argv[i] = fr_argv[reg_argc - i - 1];
359159eb9e1Ssherrym fr_argv[reg_argc - i - 1] = t;
360159eb9e1Ssherrym }
361159eb9e1Ssherrym
3622d4be7aaSRichard Lowe if (argc > reg_argc) {
3632d4be7aaSRichard Lowe size = MIN((argc - reg_argc) * sizeof (long),
3642d4be7aaSRichard Lowe sizeof (fr_argv) -
3652d4be7aaSRichard Lowe (reg_argc * sizeof (long)));
3662d4be7aaSRichard Lowe
3672d4be7aaSRichard Lowe if (mdb_tgt_vread(t, &fr_argv[reg_argc], size,
368159eb9e1Ssherrym fp + sizeof (fr)) != size)
369159eb9e1Ssherrym return (-1); /* errno has been set */
370159eb9e1Ssherrym }
3712d4be7aaSRichard Lowe } else {
372159eb9e1Ssherrym argc = 0;
3732d4be7aaSRichard Lowe }
374159eb9e1Ssherrym
375159eb9e1Ssherrym if (got_pc && func(arg, pc, argc, fr_argv, &gregs) != 0)
3767c478bd9Sstevel@tonic-gate break;
3777c478bd9Sstevel@tonic-gate
3787c478bd9Sstevel@tonic-gate kregs[KREG_RSP] = kregs[KREG_RBP];
3797c478bd9Sstevel@tonic-gate
380843e1988Sjohnlev lastfp = fp;
381843e1988Sjohnlev fp = fr.fr_savfp;
382843e1988Sjohnlev /*
383843e1988Sjohnlev * The Xen hypervisor marks a stack frame as belonging to
384843e1988Sjohnlev * an exception by inverting the bits of the pointer to
385843e1988Sjohnlev * that frame. We attempt to identify these frames by
386843e1988Sjohnlev * inverting the pointer and seeing if it is within 0xfff
387843e1988Sjohnlev * bytes of the last frame.
388843e1988Sjohnlev */
389843e1988Sjohnlev if (xpv_panic)
390843e1988Sjohnlev if ((fp != 0) && (fp < lastfp) &&
391843e1988Sjohnlev ((lastfp ^ ~fp) < 0xfff))
392843e1988Sjohnlev fp = ~fp;
393843e1988Sjohnlev
394843e1988Sjohnlev kregs[KREG_RBP] = fp;
3957c478bd9Sstevel@tonic-gate kregs[KREG_RIP] = pc = fr.fr_savpc;
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gate got_pc = (pc != 0);
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate
4007c478bd9Sstevel@tonic-gate return (0);
40154a796dfSGordon Ross
40254a796dfSGordon Ross badfp:
40354a796dfSGordon Ross mdb_printf("%p [%s]", fp, mdb_strerror(err));
40454a796dfSGordon Ross return (set_errno(err));
4057c478bd9Sstevel@tonic-gate }
4067c478bd9Sstevel@tonic-gate
4077c478bd9Sstevel@tonic-gate /*
4087c478bd9Sstevel@tonic-gate * Determine the return address for the current frame. Typically this is the
4097c478bd9Sstevel@tonic-gate * fr_savpc value from the current frame, but we also perform some special
4107c478bd9Sstevel@tonic-gate * handling to see if we are stopped on one of the first two instructions of
4117c478bd9Sstevel@tonic-gate * a typical function prologue, in which case %rbp will not be set up yet.
4127c478bd9Sstevel@tonic-gate */
4137c478bd9Sstevel@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)4147c478bd9Sstevel@tonic-gate mdb_amd64_step_out(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, kreg_t fp, kreg_t sp,
4157c478bd9Sstevel@tonic-gate mdb_instr_t curinstr)
4167c478bd9Sstevel@tonic-gate {
4177c478bd9Sstevel@tonic-gate struct frame fr;
4187c478bd9Sstevel@tonic-gate GElf_Sym s;
4197c478bd9Sstevel@tonic-gate char buf[1];
4207c478bd9Sstevel@tonic-gate
4217c478bd9Sstevel@tonic-gate enum {
4227c478bd9Sstevel@tonic-gate M_PUSHQ_RBP = 0x55, /* pushq %rbp */
4237c478bd9Sstevel@tonic-gate M_REX_W = 0x48, /* REX prefix with only W set */
4247c478bd9Sstevel@tonic-gate M_MOVL_RBP = 0x8b /* movq %rsp, %rbp with prefix */
4257c478bd9Sstevel@tonic-gate };
4267c478bd9Sstevel@tonic-gate
4277c478bd9Sstevel@tonic-gate if (mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY,
4287c478bd9Sstevel@tonic-gate buf, 0, &s, NULL) == 0) {
4297c478bd9Sstevel@tonic-gate if (pc == s.st_value && curinstr == M_PUSHQ_RBP)
4307c478bd9Sstevel@tonic-gate fp = sp - 8;
4317c478bd9Sstevel@tonic-gate else if (pc == s.st_value + 1 && curinstr == M_REX_W) {
4327c478bd9Sstevel@tonic-gate if (mdb_tgt_vread(t, &curinstr, sizeof (curinstr),
4337c478bd9Sstevel@tonic-gate pc + 1) == sizeof (curinstr) && curinstr ==
4347c478bd9Sstevel@tonic-gate M_MOVL_RBP)
4357c478bd9Sstevel@tonic-gate fp = sp;
4367c478bd9Sstevel@tonic-gate }
4377c478bd9Sstevel@tonic-gate }
4387c478bd9Sstevel@tonic-gate
4397c478bd9Sstevel@tonic-gate if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) == sizeof (fr)) {
4407c478bd9Sstevel@tonic-gate *p = fr.fr_savpc;
4417c478bd9Sstevel@tonic-gate return (0);
4427c478bd9Sstevel@tonic-gate }
4437c478bd9Sstevel@tonic-gate
4447c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */
4457c478bd9Sstevel@tonic-gate }
4467c478bd9Sstevel@tonic-gate
4477c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4487c478bd9Sstevel@tonic-gate int
mdb_amd64_next(mdb_tgt_t * t,uintptr_t * p,kreg_t pc,mdb_instr_t curinstr)4497c478bd9Sstevel@tonic-gate mdb_amd64_next(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, mdb_instr_t curinstr)
4507c478bd9Sstevel@tonic-gate {
4517c478bd9Sstevel@tonic-gate mdb_tgt_addr_t npc;
452b2c0fa2eSdmick mdb_tgt_addr_t callpc;
4537c478bd9Sstevel@tonic-gate
4547c478bd9Sstevel@tonic-gate enum {
4557c478bd9Sstevel@tonic-gate M_CALL_REL = 0xe8, /* call near with relative displacement */
4567c478bd9Sstevel@tonic-gate M_CALL_REG = 0xff, /* call near indirect or call far register */
4577c478bd9Sstevel@tonic-gate
4587c478bd9Sstevel@tonic-gate M_REX_LO = 0x40,
4597c478bd9Sstevel@tonic-gate M_REX_HI = 0x4f
4607c478bd9Sstevel@tonic-gate };
4617c478bd9Sstevel@tonic-gate
4627c478bd9Sstevel@tonic-gate /*
4637c478bd9Sstevel@tonic-gate * If the opcode is a near call with relative displacement, assume the
4647c478bd9Sstevel@tonic-gate * displacement is a rel32 from the next instruction.
4657c478bd9Sstevel@tonic-gate */
4667c478bd9Sstevel@tonic-gate if (curinstr == M_CALL_REL) {
4677c478bd9Sstevel@tonic-gate *p = pc + sizeof (mdb_instr_t) + sizeof (uint32_t);
4687c478bd9Sstevel@tonic-gate return (0);
4697c478bd9Sstevel@tonic-gate }
4707c478bd9Sstevel@tonic-gate
4717c478bd9Sstevel@tonic-gate /* Skip the rex prefix, if any */
472b2c0fa2eSdmick callpc = pc;
473b2c0fa2eSdmick while (curinstr >= M_REX_LO && curinstr <= M_REX_HI) {
474b2c0fa2eSdmick if (mdb_tgt_vread(t, &curinstr, sizeof (curinstr), ++callpc) !=
4757c478bd9Sstevel@tonic-gate sizeof (curinstr))
4767c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */
477b2c0fa2eSdmick }
4787c478bd9Sstevel@tonic-gate
4797c478bd9Sstevel@tonic-gate if (curinstr != M_CALL_REG) {
4807c478bd9Sstevel@tonic-gate /* It's not a call */
4817c478bd9Sstevel@tonic-gate return (set_errno(EAGAIN));
4827c478bd9Sstevel@tonic-gate }
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate if ((npc = mdb_dis_nextins(mdb.m_disasm, t, MDB_TGT_AS_VIRT, pc)) == pc)
4857c478bd9Sstevel@tonic-gate return (-1); /* errno is set for us */
4867c478bd9Sstevel@tonic-gate
4877c478bd9Sstevel@tonic-gate *p = npc;
4887c478bd9Sstevel@tonic-gate return (0);
4897c478bd9Sstevel@tonic-gate }
4907c478bd9Sstevel@tonic-gate
4917c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4927c478bd9Sstevel@tonic-gate int
mdb_amd64_kvm_frame(void * arglim,uintptr_t pc,uint_t argc,const long * argv,const mdb_tgt_gregset_t * gregs)4937c478bd9Sstevel@tonic-gate mdb_amd64_kvm_frame(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
4947c478bd9Sstevel@tonic-gate const mdb_tgt_gregset_t *gregs)
4957c478bd9Sstevel@tonic-gate {
4967c478bd9Sstevel@tonic-gate argc = MIN(argc, (uintptr_t)arglim);
4977c478bd9Sstevel@tonic-gate mdb_printf("%a(", pc);
4987c478bd9Sstevel@tonic-gate
4997c478bd9Sstevel@tonic-gate if (argc != 0) {
5007c478bd9Sstevel@tonic-gate mdb_printf("%lr", *argv++);
5017c478bd9Sstevel@tonic-gate for (argc--; argc != 0; argc--)
5027c478bd9Sstevel@tonic-gate mdb_printf(", %lr", *argv++);
5037c478bd9Sstevel@tonic-gate }
5047c478bd9Sstevel@tonic-gate
5057c478bd9Sstevel@tonic-gate mdb_printf(")\n");
5067c478bd9Sstevel@tonic-gate return (0);
5077c478bd9Sstevel@tonic-gate }
5087c478bd9Sstevel@tonic-gate
5097c478bd9Sstevel@tonic-gate int
mdb_amd64_kvm_framev(void * arglim,uintptr_t pc,uint_t argc,const long * argv,const mdb_tgt_gregset_t * gregs)5107c478bd9Sstevel@tonic-gate mdb_amd64_kvm_framev(void *arglim, uintptr_t pc, uint_t argc, const long *argv,
5117c478bd9Sstevel@tonic-gate const mdb_tgt_gregset_t *gregs)
5127c478bd9Sstevel@tonic-gate {
513159eb9e1Ssherrym /*
514159eb9e1Ssherrym * Historically adb limited stack trace argument display to a fixed-
515159eb9e1Ssherrym * size number of arguments since no symbolic debugging info existed.
516159eb9e1Ssherrym * On amd64 we can detect the true number of saved arguments so only
517159eb9e1Ssherrym * respect an arglim of zero; otherwise display the entire argv[].
518159eb9e1Ssherrym */
519159eb9e1Ssherrym if (arglim == 0)
520159eb9e1Ssherrym argc = 0;
521159eb9e1Ssherrym
5227c478bd9Sstevel@tonic-gate mdb_printf("%0?lr %a(", gregs->kregs[KREG_RBP], pc);
5237c478bd9Sstevel@tonic-gate
5247c478bd9Sstevel@tonic-gate if (argc != 0) {
5257c478bd9Sstevel@tonic-gate mdb_printf("%lr", *argv++);
5267c478bd9Sstevel@tonic-gate for (argc--; argc != 0; argc--)
5277c478bd9Sstevel@tonic-gate mdb_printf(", %lr", *argv++);
5287c478bd9Sstevel@tonic-gate }
5297c478bd9Sstevel@tonic-gate
5307c478bd9Sstevel@tonic-gate mdb_printf(")\n");
5317c478bd9Sstevel@tonic-gate return (0);
5327c478bd9Sstevel@tonic-gate }
533