10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include <sys/types.h> 300Sstevel@tonic-gate #include <sys/reg.h> 310Sstevel@tonic-gate #include <sys/privregs.h> 320Sstevel@tonic-gate #include <sys/stack.h> 330Sstevel@tonic-gate #include <sys/frame.h> 340Sstevel@tonic-gate 350Sstevel@tonic-gate #include <mdb/mdb_target_impl.h> 360Sstevel@tonic-gate #include <mdb/mdb_kreg_impl.h> 370Sstevel@tonic-gate #include <mdb/mdb_debug.h> 380Sstevel@tonic-gate #include <mdb/mdb_modapi.h> 390Sstevel@tonic-gate #include <mdb/mdb_amd64util.h> 40*170Ssherrym #include <mdb/mdb_ctf.h> 410Sstevel@tonic-gate #include <mdb/mdb_err.h> 420Sstevel@tonic-gate #include <mdb/mdb.h> 430Sstevel@tonic-gate 440Sstevel@tonic-gate /* 450Sstevel@tonic-gate * This array is used by the getareg and putareg entry points, and also by our 460Sstevel@tonic-gate * register variable discipline. 470Sstevel@tonic-gate */ 480Sstevel@tonic-gate 490Sstevel@tonic-gate const mdb_tgt_regdesc_t mdb_amd64_kregs[] = { 500Sstevel@tonic-gate { "savfp", KREG_SAVFP, MDB_TGT_R_EXPORT }, 510Sstevel@tonic-gate { "savpc", KREG_SAVPC, MDB_TGT_R_EXPORT }, 520Sstevel@tonic-gate { "rdi", KREG_RDI, MDB_TGT_R_EXPORT }, 530Sstevel@tonic-gate { "rsi", KREG_RSI, MDB_TGT_R_EXPORT }, 540Sstevel@tonic-gate { "rdx", KREG_RDX, MDB_TGT_R_EXPORT }, 550Sstevel@tonic-gate { "rcx", KREG_RCX, MDB_TGT_R_EXPORT }, 560Sstevel@tonic-gate { "r8", KREG_R8, MDB_TGT_R_EXPORT }, 570Sstevel@tonic-gate { "r9", KREG_R9, MDB_TGT_R_EXPORT }, 580Sstevel@tonic-gate { "rax", KREG_RAX, MDB_TGT_R_EXPORT }, 590Sstevel@tonic-gate { "rbx", KREG_RBX, MDB_TGT_R_EXPORT }, 600Sstevel@tonic-gate { "rbp", KREG_RBP, MDB_TGT_R_EXPORT }, 610Sstevel@tonic-gate { "r10", KREG_R10, MDB_TGT_R_EXPORT }, 620Sstevel@tonic-gate { "r11", KREG_R11, MDB_TGT_R_EXPORT }, 630Sstevel@tonic-gate { "r12", KREG_R12, MDB_TGT_R_EXPORT }, 640Sstevel@tonic-gate { "r13", KREG_R13, MDB_TGT_R_EXPORT }, 650Sstevel@tonic-gate { "r14", KREG_R14, MDB_TGT_R_EXPORT }, 660Sstevel@tonic-gate { "r15", KREG_R15, MDB_TGT_R_EXPORT }, 670Sstevel@tonic-gate { "fsbase", KREG_FSBASE, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV }, 680Sstevel@tonic-gate { "gsbase", KREG_GSBASE, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV }, 690Sstevel@tonic-gate { "kgsbase", KREG_KGSBASE, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV }, 700Sstevel@tonic-gate { "ds", KREG_DS, MDB_TGT_R_EXPORT }, 710Sstevel@tonic-gate { "es", KREG_ES, MDB_TGT_R_EXPORT }, 720Sstevel@tonic-gate { "fs", KREG_FS, MDB_TGT_R_EXPORT }, 730Sstevel@tonic-gate { "gs", KREG_GS, MDB_TGT_R_EXPORT }, 740Sstevel@tonic-gate { "trapno", KREG_TRAPNO, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV }, 750Sstevel@tonic-gate { "err", KREG_ERR, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV }, 760Sstevel@tonic-gate { "rip", KREG_RIP, MDB_TGT_R_EXPORT }, 770Sstevel@tonic-gate { "cs", KREG_CS, MDB_TGT_R_EXPORT }, 780Sstevel@tonic-gate { "rflags", KREG_RFLAGS, MDB_TGT_R_EXPORT }, 790Sstevel@tonic-gate { "rsp", KREG_RSP, MDB_TGT_R_EXPORT }, 800Sstevel@tonic-gate { "ss", KREG_SS, MDB_TGT_R_EXPORT }, 810Sstevel@tonic-gate { NULL, 0, 0 } 820Sstevel@tonic-gate }; 830Sstevel@tonic-gate 840Sstevel@tonic-gate void 850Sstevel@tonic-gate mdb_amd64_printregs(const mdb_tgt_gregset_t *gregs) 860Sstevel@tonic-gate { 870Sstevel@tonic-gate const kreg_t *kregs = &gregs->kregs[0]; 880Sstevel@tonic-gate kreg_t rflags = kregs[KREG_RFLAGS]; 890Sstevel@tonic-gate 900Sstevel@tonic-gate #define GETREG2(x) ((uintptr_t)kregs[(x)]), ((uintptr_t)kregs[(x)]) 910Sstevel@tonic-gate 920Sstevel@tonic-gate mdb_printf("%%rax = 0x%0?p %15A %%r9 = 0x%0?p %A\n", 930Sstevel@tonic-gate GETREG2(KREG_RAX), GETREG2(KREG_R9)); 940Sstevel@tonic-gate mdb_printf("%%rbx = 0x%0?p %15A %%r10 = 0x%0?p %A\n", 950Sstevel@tonic-gate GETREG2(KREG_RBX), GETREG2(KREG_R10)); 960Sstevel@tonic-gate mdb_printf("%%rcx = 0x%0?p %15A %%r11 = 0x%0?p %A\n", 970Sstevel@tonic-gate GETREG2(KREG_RCX), GETREG2(KREG_R11)); 980Sstevel@tonic-gate mdb_printf("%%rdx = 0x%0?p %15A %%r12 = 0x%0?p %A\n", 990Sstevel@tonic-gate GETREG2(KREG_RDX), GETREG2(KREG_R12)); 1000Sstevel@tonic-gate mdb_printf("%%rsi = 0x%0?p %15A %%r13 = 0x%0?p %A\n", 1010Sstevel@tonic-gate GETREG2(KREG_RSI), GETREG2(KREG_R13)); 1020Sstevel@tonic-gate mdb_printf("%%rdi = 0x%0?p %15A %%r14 = 0x%0?p %A\n", 1030Sstevel@tonic-gate GETREG2(KREG_RDI), GETREG2(KREG_R14)); 1040Sstevel@tonic-gate mdb_printf("%%r8 = 0x%0?p %15A %%r15 = 0x%0?p %A\n\n", 1050Sstevel@tonic-gate GETREG2(KREG_R8), GETREG2(KREG_R15)); 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate mdb_printf("%%rip = 0x%0?p %A\n", GETREG2(KREG_RIP)); 1080Sstevel@tonic-gate mdb_printf("%%rbp = 0x%0?p\n", kregs[KREG_RBP]); 1090Sstevel@tonic-gate mdb_printf("%%rsp = 0x%0?p\n", kregs[KREG_RSP]); 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate mdb_printf("%%rflags = 0x%08x\n", rflags); 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate mdb_printf(" id=%u vip=%u vif=%u ac=%u vm=%u rf=%u nt=%u iopl=0x%x\n", 1140Sstevel@tonic-gate (rflags & KREG_EFLAGS_ID_MASK) >> KREG_EFLAGS_ID_SHIFT, 1150Sstevel@tonic-gate (rflags & KREG_EFLAGS_VIP_MASK) >> KREG_EFLAGS_VIP_SHIFT, 1160Sstevel@tonic-gate (rflags & KREG_EFLAGS_VIF_MASK) >> KREG_EFLAGS_VIF_SHIFT, 1170Sstevel@tonic-gate (rflags & KREG_EFLAGS_AC_MASK) >> KREG_EFLAGS_AC_SHIFT, 1180Sstevel@tonic-gate (rflags & KREG_EFLAGS_VM_MASK) >> KREG_EFLAGS_VM_SHIFT, 1190Sstevel@tonic-gate (rflags & KREG_EFLAGS_RF_MASK) >> KREG_EFLAGS_RF_SHIFT, 1200Sstevel@tonic-gate (rflags & KREG_EFLAGS_NT_MASK) >> KREG_EFLAGS_NT_SHIFT, 1210Sstevel@tonic-gate (rflags & KREG_EFLAGS_IOPL_MASK) >> KREG_EFLAGS_IOPL_SHIFT); 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate mdb_printf(" status=<%s,%s,%s,%s,%s,%s,%s,%s,%s>\n\n", 1240Sstevel@tonic-gate (rflags & KREG_EFLAGS_OF_MASK) ? "OF" : "of", 1250Sstevel@tonic-gate (rflags & KREG_EFLAGS_DF_MASK) ? "DF" : "df", 1260Sstevel@tonic-gate (rflags & KREG_EFLAGS_IF_MASK) ? "IF" : "if", 1270Sstevel@tonic-gate (rflags & KREG_EFLAGS_TF_MASK) ? "TF" : "tf", 1280Sstevel@tonic-gate (rflags & KREG_EFLAGS_SF_MASK) ? "SF" : "sf", 1290Sstevel@tonic-gate (rflags & KREG_EFLAGS_ZF_MASK) ? "ZF" : "zf", 1300Sstevel@tonic-gate (rflags & KREG_EFLAGS_AF_MASK) ? "AF" : "af", 1310Sstevel@tonic-gate (rflags & KREG_EFLAGS_PF_MASK) ? "PF" : "pf", 1320Sstevel@tonic-gate (rflags & KREG_EFLAGS_CF_MASK) ? "CF" : "cf"); 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate mdb_printf("%24s%%cs = 0x%04x\t%%ds = 0x%04x\t%%es = 0x%04x\n", 1350Sstevel@tonic-gate " ", kregs[KREG_CS], kregs[KREG_DS], kregs[KREG_ES]); 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate mdb_printf("%%trapno = 0x%x\t\t%%fs = 0x%04x\tfsbase = 0x%0?p\n", 1380Sstevel@tonic-gate kregs[KREG_TRAPNO], (kregs[KREG_FS] & 0xffff), kregs[KREG_FSBASE]); 1390Sstevel@tonic-gate mdb_printf(" %%err = 0x%x\t\t%%gs = 0x%04x\tgsbase = 0x%0?p\n", 1400Sstevel@tonic-gate kregs[KREG_ERR], (kregs[KREG_GS] & 0xffff), kregs[KREG_GSBASE]); 1410Sstevel@tonic-gate } 1420Sstevel@tonic-gate 143*170Ssherrym 144*170Ssherrym 145*170Ssherrym /* 146*170Ssherrym * Sun Studio 10 patch compiler and gcc 3.4.3 Sun branch implemented a 147*170Ssherrym * "-save_args" option on amd64. When the option is specified, INTEGER 148*170Ssherrym * type function arguments passed via registers will be saved on the stack 149*170Ssherrym * immediately after %rbp, and will not be modified through out the life 150*170Ssherrym * of the routine. 151*170Ssherrym * 152*170Ssherrym * +--------+ 153*170Ssherrym * %rbp --> | %rbp | 154*170Ssherrym * +--------+ 155*170Ssherrym * -0x8(%rbp) | %rdi | 156*170Ssherrym * +--------+ 157*170Ssherrym * -0x10(%rbp) | %rsi | 158*170Ssherrym * +--------+ 159*170Ssherrym * -0x18(%rbp) | %rdx | 160*170Ssherrym * +--------+ 161*170Ssherrym * -0x20(%rbp) | %rcx | 162*170Ssherrym * +--------+ 163*170Ssherrym * -0x28(%rbp) | %r8 | 164*170Ssherrym * +--------+ 165*170Ssherrym * -0x30(%rbp) | %r9 | 166*170Ssherrym * +--------+ 167*170Ssherrym * 168*170Ssherrym * 169*170Ssherrym * For example, for the following function, 170*170Ssherrym * 171*170Ssherrym * void 172*170Ssherrym * foo(int a1, int a2, int a3, int a4, int a5, int a6, int a7) 173*170Ssherrym * { 174*170Ssherrym * ... 175*170Ssherrym * } 176*170Ssherrym * 177*170Ssherrym * Disassembled code will look something like the following: 178*170Ssherrym * 179*170Ssherrym * pushq %rbp 180*170Ssherrym * movq %rsp, %rbp 181*170Ssherrym * subq $imm8, %rsp ** 182*170Ssherrym * movq %rdi, -0x8(%rbp) 183*170Ssherrym * movq %rsi, -0x10(%rbp) 184*170Ssherrym * movq %rdx, -0x18(%rbp) 185*170Ssherrym * movq %rcx, -0x20(%rbp) 186*170Ssherrym * movq %r8, -0x28(%rbp) 187*170Ssherrym * movq %r9, -0x30(%rbp) 188*170Ssherrym * ... 189*170Ssherrym * or 190*170Ssherrym * pushq %rbp 191*170Ssherrym * movq %rsp, %rbp 192*170Ssherrym * subq $imm8, %rsp ** 193*170Ssherrym * movq %r9, -0x30(%rbp) 194*170Ssherrym * movq %r8, -0x28(%rbp) 195*170Ssherrym * movq %rcx, -0x20(%rbp) 196*170Ssherrym * movq %rdx, -0x18(%rbp) 197*170Ssherrym * movq %rsi, -0x10(%rbp) 198*170Ssherrym * movq %rdi, -0x8(%rbp) 199*170Ssherrym * ... 200*170Ssherrym * 201*170Ssherrym * **: The space being reserved is in addition to what the current 202*170Ssherrym * function prolog already reserves. 203*170Ssherrym * 204*170Ssherrym * If there are odd number of arguments to a function, additional space is 205*170Ssherrym * reserved on the stack to maintain 16-byte alignment. For example, 206*170Ssherrym * 207*170Ssherrym * argc == 0: no argument saving. 208*170Ssherrym * argc == 3: save 3, but space for 4 is reserved 209*170Ssherrym * argc == 7: save 6. 210*170Ssherrym */ 211*170Ssherrym 212*170Ssherrym /* 213*170Ssherrym * The longest instruction sequence in bytes before all 6 arguments are 214*170Ssherrym * saved on the stack. This value depends on compiler implementation, 215*170Ssherrym * therefore it should be examined periodically to guarantee accuracy. 216*170Ssherrym */ 217*170Ssherrym #define SEQ_LEN 80 218*170Ssherrym 219*170Ssherrym /* 220*170Ssherrym * Size of the instruction sequence arrays. It should correspond to 221*170Ssherrym * the maximum number of arguments passed via registers. 222*170Ssherrym */ 223*170Ssherrym #define INSTR_ARRAY_SIZE 6 224*170Ssherrym 225*170Ssherrym #define INSTR4(ins, off) \ 226*170Ssherrym (ins[(off)] + (ins[(off) + 1] << 8) + (ins[(off + 2)] << 16) + \ 227*170Ssherrym (ins[(off) + 3] << 24)) 228*170Ssherrym 229*170Ssherrym /* 230*170Ssherrym * Sun Studio 10 patch implementation saves %rdi first; 231*170Ssherrym * GCC 3.4.3 Sun branch implementation saves them in reverse order. 232*170Ssherrym */ 233*170Ssherrym static const uint32_t save_instr[INSTR_ARRAY_SIZE] = { 234*170Ssherrym 0xf87d8948, /* movq %rdi, -0x8(%rbp) */ 235*170Ssherrym 0xf0758948, /* movq %rsi, -0x10(%rbp) */ 236*170Ssherrym 0xe8558948, /* movq %rdx, -0x18(%rbp) */ 237*170Ssherrym 0xe04d8948, /* movq %rcx, -0x20(%rbp) */ 238*170Ssherrym 0xd845894c, /* movq %r8, -0x28(%rbp) */ 239*170Ssherrym 0xd04d894c /* movq %r9, -0x30(%rbp) */ 240*170Ssherrym }; 241*170Ssherrym 242*170Ssherrym static const uint32_t save_fp_instr[2] = { 243*170Ssherrym 0xe5894855, /* pushq %rbp; movq %rsp,%rbp, encoding 1 */ 244*170Ssherrym 0xec8b4855 /* pushq %rbp; movq %rsp,%rbp, encoding 2 */ 245*170Ssherrym }; 246*170Ssherrym 247*170Ssherrym /* 248*170Ssherrym * Look for the above instruction sequences as indicators for register 249*170Ssherrym * arguments being available on the stack. 250*170Ssherrym */ 251*170Ssherrym static int 252*170Ssherrym is_argsaved(mdb_tgt_t *t, uintptr_t fstart, uint64_t size, uint_t argc, 253*170Ssherrym int start_index) 254*170Ssherrym { 255*170Ssherrym uint8_t ins[SEQ_LEN]; 256*170Ssherrym int i, j; 257*170Ssherrym uint32_t n; 258*170Ssherrym 259*170Ssherrym size = MIN(size, SEQ_LEN); 260*170Ssherrym argc = MIN((start_index + argc), INSTR_ARRAY_SIZE); 261*170Ssherrym 262*170Ssherrym if (mdb_tgt_vread(t, ins, size, fstart) != size) 263*170Ssherrym return (0); 264*170Ssherrym 265*170Ssherrym /* 266*170Ssherrym * Make sure framepointer has been saved. 267*170Ssherrym */ 268*170Ssherrym n = INSTR4(ins, 0); 269*170Ssherrym for (i = 0; i < 2; i++) { 270*170Ssherrym if (n == save_fp_instr[i]) 271*170Ssherrym break; 272*170Ssherrym } 273*170Ssherrym 274*170Ssherrym if (i >= 2) 275*170Ssherrym return (0); 276*170Ssherrym 277*170Ssherrym /* 278*170Ssherrym * Compare against Sun Studio implementation 279*170Ssherrym */ 280*170Ssherrym for (i = 8, j = start_index; i < size - 4; i++) { 281*170Ssherrym n = INSTR4(ins, i); 282*170Ssherrym 283*170Ssherrym if (n == save_instr[j]) { 284*170Ssherrym i += 3; 285*170Ssherrym if (++j >= argc) 286*170Ssherrym return (1); 287*170Ssherrym } 288*170Ssherrym } 289*170Ssherrym 290*170Ssherrym /* 291*170Ssherrym * Compare against GCC implementation 292*170Ssherrym */ 293*170Ssherrym for (i = 8, j = argc - 1; i < size - 4; i++) { 294*170Ssherrym n = INSTR4(ins, i); 295*170Ssherrym 296*170Ssherrym if (n == save_instr[j]) { 297*170Ssherrym i += 3; 298*170Ssherrym if (--j < start_index) 299*170Ssherrym return (1); 300*170Ssherrym } 301*170Ssherrym } 302*170Ssherrym 303*170Ssherrym return (0); 304*170Ssherrym } 305*170Ssherrym 3060Sstevel@tonic-gate int 3070Sstevel@tonic-gate mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp, 3080Sstevel@tonic-gate mdb_tgt_stack_f *func, void *arg) 3090Sstevel@tonic-gate { 3100Sstevel@tonic-gate mdb_tgt_gregset_t gregs; 3110Sstevel@tonic-gate kreg_t *kregs = &gregs.kregs[0]; 3120Sstevel@tonic-gate int got_pc = (gsp->kregs[KREG_RIP] != 0); 313*170Ssherrym uint_t argc, reg_argc; 314*170Ssherrym long fr_argv[32]; 315*170Ssherrym int start_index; /* index to save_instr where to start comparison */ 316*170Ssherrym int i; 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate struct { 3190Sstevel@tonic-gate uintptr_t fr_savfp; 3200Sstevel@tonic-gate uintptr_t fr_savpc; 3210Sstevel@tonic-gate } fr; 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate uintptr_t fp = gsp->kregs[KREG_RBP]; 3240Sstevel@tonic-gate uintptr_t pc = gsp->kregs[KREG_RIP]; 325*170Ssherrym uintptr_t curpc; 326*170Ssherrym 327*170Ssherrym ssize_t size; 328*170Ssherrym 329*170Ssherrym GElf_Sym s; 330*170Ssherrym mdb_syminfo_t sip; 331*170Ssherrym mdb_ctf_funcinfo_t mfp; 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate bcopy(gsp, &gregs, sizeof (gregs)); 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate while (fp != 0) { 3360Sstevel@tonic-gate 337*170Ssherrym curpc = pc; 338*170Ssherrym 3390Sstevel@tonic-gate if (fp & (STACK_ALIGN - 1)) 3400Sstevel@tonic-gate return (set_errno(EMDB_STKALIGN)); 3410Sstevel@tonic-gate 342*170Ssherrym if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) != sizeof (fr)) 343*170Ssherrym return (-1); /* errno has been set for us */ 344*170Ssherrym 345*170Ssherrym if ((mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY, 346*170Ssherrym NULL, 0, &s, &sip) == 0) && 347*170Ssherrym (mdb_ctf_func_info(&s, &sip, &mfp) == 0)) { 348*170Ssherrym int return_type = mdb_ctf_type_kind(mfp.mtf_return); 349*170Ssherrym argc = mfp.mtf_argc; 350*170Ssherrym /* 351*170Ssherrym * If the function returns a structure or union, 352*170Ssherrym * %rdi contains the address in which to store the 353*170Ssherrym * return value rather than for an argument. 354*170Ssherrym */ 355*170Ssherrym if (return_type == CTF_K_STRUCT || 356*170Ssherrym return_type == CTF_K_UNION) 357*170Ssherrym start_index = 1; 358*170Ssherrym else 359*170Ssherrym start_index = 0; 360*170Ssherrym } else { 361*170Ssherrym argc = 0; 362*170Ssherrym } 363*170Ssherrym 364*170Ssherrym if (argc != 0 && is_argsaved(t, s.st_value, s.st_size, 365*170Ssherrym argc, start_index)) { 3660Sstevel@tonic-gate 367*170Ssherrym /* Upto to 6 arguments are passed via registers */ 368*170Ssherrym reg_argc = MIN(6, mfp.mtf_argc); 369*170Ssherrym size = reg_argc * sizeof (long); 370*170Ssherrym 371*170Ssherrym if (mdb_tgt_vread(t, fr_argv, size, (fp - size)) 372*170Ssherrym != size) 373*170Ssherrym return (-1); /* errno has been set for us */ 374*170Ssherrym 375*170Ssherrym /* 376*170Ssherrym * Arrange the arguments in the right order for 377*170Ssherrym * printing. 378*170Ssherrym */ 379*170Ssherrym for (i = 0; i < (reg_argc >> 1); i++) { 380*170Ssherrym long t = fr_argv[i]; 381*170Ssherrym 382*170Ssherrym fr_argv[i] = fr_argv[reg_argc - i - 1]; 383*170Ssherrym fr_argv[reg_argc - i - 1] = t; 384*170Ssherrym } 385*170Ssherrym 386*170Ssherrym if (argc > 6) { 387*170Ssherrym size = (argc - 6) * sizeof (long); 388*170Ssherrym if (mdb_tgt_vread(t, &fr_argv[6], size, 389*170Ssherrym fp + sizeof (fr)) != size) 390*170Ssherrym return (-1); /* errno has been set */ 391*170Ssherrym } 392*170Ssherrym } else 393*170Ssherrym argc = 0; 394*170Ssherrym 395*170Ssherrym if (got_pc && func(arg, pc, argc, fr_argv, &gregs) != 0) 3960Sstevel@tonic-gate break; 3970Sstevel@tonic-gate 3980Sstevel@tonic-gate kregs[KREG_RSP] = kregs[KREG_RBP]; 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate kregs[KREG_RBP] = fp = fr.fr_savfp; 4010Sstevel@tonic-gate kregs[KREG_RIP] = pc = fr.fr_savpc; 4020Sstevel@tonic-gate 403*170Ssherrym if (curpc == pc) 404*170Ssherrym break; 405*170Ssherrym 4060Sstevel@tonic-gate got_pc = (pc != 0); 4070Sstevel@tonic-gate } 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate return (0); 4100Sstevel@tonic-gate } 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate /* 4130Sstevel@tonic-gate * Determine the return address for the current frame. Typically this is the 4140Sstevel@tonic-gate * fr_savpc value from the current frame, but we also perform some special 4150Sstevel@tonic-gate * handling to see if we are stopped on one of the first two instructions of 4160Sstevel@tonic-gate * a typical function prologue, in which case %rbp will not be set up yet. 4170Sstevel@tonic-gate */ 4180Sstevel@tonic-gate int 4190Sstevel@tonic-gate mdb_amd64_step_out(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, kreg_t fp, kreg_t sp, 4200Sstevel@tonic-gate mdb_instr_t curinstr) 4210Sstevel@tonic-gate { 4220Sstevel@tonic-gate struct frame fr; 4230Sstevel@tonic-gate GElf_Sym s; 4240Sstevel@tonic-gate char buf[1]; 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate enum { 4270Sstevel@tonic-gate M_PUSHQ_RBP = 0x55, /* pushq %rbp */ 4280Sstevel@tonic-gate M_REX_W = 0x48, /* REX prefix with only W set */ 4290Sstevel@tonic-gate M_MOVL_RBP = 0x8b /* movq %rsp, %rbp with prefix */ 4300Sstevel@tonic-gate }; 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate if (mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY, 4330Sstevel@tonic-gate buf, 0, &s, NULL) == 0) { 4340Sstevel@tonic-gate if (pc == s.st_value && curinstr == M_PUSHQ_RBP) 4350Sstevel@tonic-gate fp = sp - 8; 4360Sstevel@tonic-gate else if (pc == s.st_value + 1 && curinstr == M_REX_W) { 4370Sstevel@tonic-gate if (mdb_tgt_vread(t, &curinstr, sizeof (curinstr), 4380Sstevel@tonic-gate pc + 1) == sizeof (curinstr) && curinstr == 4390Sstevel@tonic-gate M_MOVL_RBP) 4400Sstevel@tonic-gate fp = sp; 4410Sstevel@tonic-gate } 4420Sstevel@tonic-gate } 4430Sstevel@tonic-gate 4440Sstevel@tonic-gate if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) == sizeof (fr)) { 4450Sstevel@tonic-gate *p = fr.fr_savpc; 4460Sstevel@tonic-gate return (0); 4470Sstevel@tonic-gate } 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate return (-1); /* errno is set for us */ 4500Sstevel@tonic-gate } 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate /*ARGSUSED*/ 4530Sstevel@tonic-gate int 4540Sstevel@tonic-gate mdb_amd64_next(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, mdb_instr_t curinstr) 4550Sstevel@tonic-gate { 4560Sstevel@tonic-gate mdb_tgt_addr_t npc; 4570Sstevel@tonic-gate 4580Sstevel@tonic-gate enum { 4590Sstevel@tonic-gate M_CALL_REL = 0xe8, /* call near with relative displacement */ 4600Sstevel@tonic-gate M_CALL_REG = 0xff, /* call near indirect or call far register */ 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate M_REX_LO = 0x40, 4630Sstevel@tonic-gate M_REX_HI = 0x4f 4640Sstevel@tonic-gate }; 4650Sstevel@tonic-gate 4660Sstevel@tonic-gate /* 4670Sstevel@tonic-gate * If the opcode is a near call with relative displacement, assume the 4680Sstevel@tonic-gate * displacement is a rel32 from the next instruction. 4690Sstevel@tonic-gate */ 4700Sstevel@tonic-gate if (curinstr == M_CALL_REL) { 4710Sstevel@tonic-gate *p = pc + sizeof (mdb_instr_t) + sizeof (uint32_t); 4720Sstevel@tonic-gate return (0); 4730Sstevel@tonic-gate } 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate /* Skip the rex prefix, if any */ 4760Sstevel@tonic-gate if (curinstr >= M_REX_LO && curinstr <= M_REX_HI && 4770Sstevel@tonic-gate mdb_tgt_vread(t, &curinstr, sizeof (curinstr), pc) != 4780Sstevel@tonic-gate sizeof (curinstr)) 4790Sstevel@tonic-gate return (-1); /* errno is set for us */ 4800Sstevel@tonic-gate 4810Sstevel@tonic-gate if (curinstr != M_CALL_REG) { 4820Sstevel@tonic-gate /* It's not a call */ 4830Sstevel@tonic-gate return (set_errno(EAGAIN)); 4840Sstevel@tonic-gate } 4850Sstevel@tonic-gate 4860Sstevel@tonic-gate if ((npc = mdb_dis_nextins(mdb.m_disasm, t, MDB_TGT_AS_VIRT, pc)) == pc) 4870Sstevel@tonic-gate return (-1); /* errno is set for us */ 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate *p = npc; 4900Sstevel@tonic-gate return (0); 4910Sstevel@tonic-gate } 4920Sstevel@tonic-gate 4930Sstevel@tonic-gate /*ARGSUSED*/ 4940Sstevel@tonic-gate int 4950Sstevel@tonic-gate mdb_amd64_kvm_frame(void *arglim, uintptr_t pc, uint_t argc, const long *argv, 4960Sstevel@tonic-gate const mdb_tgt_gregset_t *gregs) 4970Sstevel@tonic-gate { 4980Sstevel@tonic-gate argc = MIN(argc, (uintptr_t)arglim); 4990Sstevel@tonic-gate mdb_printf("%a(", pc); 5000Sstevel@tonic-gate 5010Sstevel@tonic-gate if (argc != 0) { 5020Sstevel@tonic-gate mdb_printf("%lr", *argv++); 5030Sstevel@tonic-gate for (argc--; argc != 0; argc--) 5040Sstevel@tonic-gate mdb_printf(", %lr", *argv++); 5050Sstevel@tonic-gate } 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate mdb_printf(")\n"); 5080Sstevel@tonic-gate return (0); 5090Sstevel@tonic-gate } 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate int 5120Sstevel@tonic-gate mdb_amd64_kvm_framev(void *arglim, uintptr_t pc, uint_t argc, const long *argv, 5130Sstevel@tonic-gate const mdb_tgt_gregset_t *gregs) 5140Sstevel@tonic-gate { 515*170Ssherrym /* 516*170Ssherrym * Historically adb limited stack trace argument display to a fixed- 517*170Ssherrym * size number of arguments since no symbolic debugging info existed. 518*170Ssherrym * On amd64 we can detect the true number of saved arguments so only 519*170Ssherrym * respect an arglim of zero; otherwise display the entire argv[]. 520*170Ssherrym */ 521*170Ssherrym if (arglim == 0) 522*170Ssherrym argc = 0; 523*170Ssherrym 5240Sstevel@tonic-gate mdb_printf("%0?lr %a(", gregs->kregs[KREG_RBP], pc); 5250Sstevel@tonic-gate 5260Sstevel@tonic-gate if (argc != 0) { 5270Sstevel@tonic-gate mdb_printf("%lr", *argv++); 5280Sstevel@tonic-gate for (argc--; argc != 0; argc--) 5290Sstevel@tonic-gate mdb_printf(", %lr", *argv++); 5300Sstevel@tonic-gate } 5310Sstevel@tonic-gate 5320Sstevel@tonic-gate mdb_printf(")\n"); 5330Sstevel@tonic-gate return (0); 5340Sstevel@tonic-gate } 535