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