1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 2244 dmick * Common Development and Distribution License (the "License"). 6 2244 dmick * You may not use this file except in compliance with the License. 7 0 stevel * 8 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 0 stevel * or http://www.opensolaris.org/os/licensing. 10 0 stevel * See the License for the specific language governing permissions 11 0 stevel * and limitations under the License. 12 0 stevel * 13 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 14 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 0 stevel * If applicable, add the following below this CDDL HEADER, with the 16 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 17 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 18 0 stevel * 19 0 stevel * CDDL HEADER END 20 0 stevel */ 21 2244 dmick 22 0 stevel /* 23 3446 mrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 0 stevel * Use is subject to license terms. 25 0 stevel */ 26 0 stevel 27 0 stevel #pragma ident "%Z%%M% %I% %E% SMI" 28 0 stevel 29 0 stevel #include <sys/types.h> 30 0 stevel #include <sys/reg.h> 31 0 stevel #include <sys/privregs.h> 32 0 stevel #include <sys/stack.h> 33 0 stevel #include <sys/frame.h> 34 0 stevel 35 0 stevel #include <mdb/mdb_target_impl.h> 36 0 stevel #include <mdb/mdb_kreg_impl.h> 37 0 stevel #include <mdb/mdb_debug.h> 38 0 stevel #include <mdb/mdb_modapi.h> 39 0 stevel #include <mdb/mdb_amd64util.h> 40 170 sherrym #include <mdb/mdb_ctf.h> 41 0 stevel #include <mdb/mdb_err.h> 42 0 stevel #include <mdb/mdb.h> 43 0 stevel 44 0 stevel /* 45 0 stevel * This array is used by the getareg and putareg entry points, and also by our 46 0 stevel * register variable discipline. 47 0 stevel */ 48 0 stevel 49 0 stevel const mdb_tgt_regdesc_t mdb_amd64_kregs[] = { 50 0 stevel { "savfp", KREG_SAVFP, MDB_TGT_R_EXPORT }, 51 0 stevel { "savpc", KREG_SAVPC, MDB_TGT_R_EXPORT }, 52 0 stevel { "rdi", KREG_RDI, MDB_TGT_R_EXPORT }, 53 0 stevel { "rsi", KREG_RSI, MDB_TGT_R_EXPORT }, 54 0 stevel { "rdx", KREG_RDX, MDB_TGT_R_EXPORT }, 55 0 stevel { "rcx", KREG_RCX, MDB_TGT_R_EXPORT }, 56 0 stevel { "r8", KREG_R8, MDB_TGT_R_EXPORT }, 57 0 stevel { "r9", KREG_R9, MDB_TGT_R_EXPORT }, 58 0 stevel { "rax", KREG_RAX, MDB_TGT_R_EXPORT }, 59 0 stevel { "rbx", KREG_RBX, MDB_TGT_R_EXPORT }, 60 0 stevel { "rbp", KREG_RBP, MDB_TGT_R_EXPORT }, 61 0 stevel { "r10", KREG_R10, MDB_TGT_R_EXPORT }, 62 0 stevel { "r11", KREG_R11, MDB_TGT_R_EXPORT }, 63 0 stevel { "r12", KREG_R12, MDB_TGT_R_EXPORT }, 64 0 stevel { "r13", KREG_R13, MDB_TGT_R_EXPORT }, 65 0 stevel { "r14", KREG_R14, MDB_TGT_R_EXPORT }, 66 0 stevel { "r15", KREG_R15, MDB_TGT_R_EXPORT }, 67 0 stevel { "ds", KREG_DS, MDB_TGT_R_EXPORT }, 68 0 stevel { "es", KREG_ES, MDB_TGT_R_EXPORT }, 69 0 stevel { "fs", KREG_FS, MDB_TGT_R_EXPORT }, 70 0 stevel { "gs", KREG_GS, MDB_TGT_R_EXPORT }, 71 0 stevel { "trapno", KREG_TRAPNO, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV }, 72 0 stevel { "err", KREG_ERR, MDB_TGT_R_EXPORT | MDB_TGT_R_PRIV }, 73 0 stevel { "rip", KREG_RIP, MDB_TGT_R_EXPORT }, 74 0 stevel { "cs", KREG_CS, MDB_TGT_R_EXPORT }, 75 0 stevel { "rflags", KREG_RFLAGS, MDB_TGT_R_EXPORT }, 76 0 stevel { "rsp", KREG_RSP, MDB_TGT_R_EXPORT }, 77 0 stevel { "ss", KREG_SS, MDB_TGT_R_EXPORT }, 78 0 stevel { NULL, 0, 0 } 79 0 stevel }; 80 0 stevel 81 0 stevel void 82 0 stevel mdb_amd64_printregs(const mdb_tgt_gregset_t *gregs) 83 0 stevel { 84 0 stevel const kreg_t *kregs = &gregs->kregs[0]; 85 0 stevel kreg_t rflags = kregs[KREG_RFLAGS]; 86 0 stevel 87 0 stevel #define GETREG2(x) ((uintptr_t)kregs[(x)]), ((uintptr_t)kregs[(x)]) 88 0 stevel 89 0 stevel mdb_printf("%%rax = 0x%0?p %15A %%r9 = 0x%0?p %A\n", 90 0 stevel GETREG2(KREG_RAX), GETREG2(KREG_R9)); 91 0 stevel mdb_printf("%%rbx = 0x%0?p %15A %%r10 = 0x%0?p %A\n", 92 0 stevel GETREG2(KREG_RBX), GETREG2(KREG_R10)); 93 0 stevel mdb_printf("%%rcx = 0x%0?p %15A %%r11 = 0x%0?p %A\n", 94 0 stevel GETREG2(KREG_RCX), GETREG2(KREG_R11)); 95 0 stevel mdb_printf("%%rdx = 0x%0?p %15A %%r12 = 0x%0?p %A\n", 96 0 stevel GETREG2(KREG_RDX), GETREG2(KREG_R12)); 97 0 stevel mdb_printf("%%rsi = 0x%0?p %15A %%r13 = 0x%0?p %A\n", 98 0 stevel GETREG2(KREG_RSI), GETREG2(KREG_R13)); 99 0 stevel mdb_printf("%%rdi = 0x%0?p %15A %%r14 = 0x%0?p %A\n", 100 0 stevel GETREG2(KREG_RDI), GETREG2(KREG_R14)); 101 0 stevel mdb_printf("%%r8 = 0x%0?p %15A %%r15 = 0x%0?p %A\n\n", 102 0 stevel GETREG2(KREG_R8), GETREG2(KREG_R15)); 103 0 stevel 104 0 stevel mdb_printf("%%rip = 0x%0?p %A\n", GETREG2(KREG_RIP)); 105 0 stevel mdb_printf("%%rbp = 0x%0?p\n", kregs[KREG_RBP]); 106 0 stevel mdb_printf("%%rsp = 0x%0?p\n", kregs[KREG_RSP]); 107 0 stevel 108 0 stevel mdb_printf("%%rflags = 0x%08x\n", rflags); 109 0 stevel 110 0 stevel mdb_printf(" id=%u vip=%u vif=%u ac=%u vm=%u rf=%u nt=%u iopl=0x%x\n", 111 0 stevel (rflags & KREG_EFLAGS_ID_MASK) >> KREG_EFLAGS_ID_SHIFT, 112 0 stevel (rflags & KREG_EFLAGS_VIP_MASK) >> KREG_EFLAGS_VIP_SHIFT, 113 0 stevel (rflags & KREG_EFLAGS_VIF_MASK) >> KREG_EFLAGS_VIF_SHIFT, 114 0 stevel (rflags & KREG_EFLAGS_AC_MASK) >> KREG_EFLAGS_AC_SHIFT, 115 0 stevel (rflags & KREG_EFLAGS_VM_MASK) >> KREG_EFLAGS_VM_SHIFT, 116 0 stevel (rflags & KREG_EFLAGS_RF_MASK) >> KREG_EFLAGS_RF_SHIFT, 117 0 stevel (rflags & KREG_EFLAGS_NT_MASK) >> KREG_EFLAGS_NT_SHIFT, 118 0 stevel (rflags & KREG_EFLAGS_IOPL_MASK) >> KREG_EFLAGS_IOPL_SHIFT); 119 0 stevel 120 0 stevel mdb_printf(" status=<%s,%s,%s,%s,%s,%s,%s,%s,%s>\n\n", 121 0 stevel (rflags & KREG_EFLAGS_OF_MASK) ? "OF" : "of", 122 0 stevel (rflags & KREG_EFLAGS_DF_MASK) ? "DF" : "df", 123 0 stevel (rflags & KREG_EFLAGS_IF_MASK) ? "IF" : "if", 124 0 stevel (rflags & KREG_EFLAGS_TF_MASK) ? "TF" : "tf", 125 0 stevel (rflags & KREG_EFLAGS_SF_MASK) ? "SF" : "sf", 126 0 stevel (rflags & KREG_EFLAGS_ZF_MASK) ? "ZF" : "zf", 127 0 stevel (rflags & KREG_EFLAGS_AF_MASK) ? "AF" : "af", 128 0 stevel (rflags & KREG_EFLAGS_PF_MASK) ? "PF" : "pf", 129 0 stevel (rflags & KREG_EFLAGS_CF_MASK) ? "CF" : "cf"); 130 0 stevel 131 0 stevel mdb_printf("%24s%%cs = 0x%04x\t%%ds = 0x%04x\t%%es = 0x%04x\n", 132 0 stevel " ", kregs[KREG_CS], kregs[KREG_DS], kregs[KREG_ES]); 133 0 stevel 134 3446 mrj mdb_printf("%%trapno = 0x%x\t\t%%fs = 0x%04x\t%%gs = 0x%04x\n", 135 3446 mrj kregs[KREG_TRAPNO], (kregs[KREG_FS] & 0xffff), 136 3446 mrj (kregs[KREG_GS] & 0xffff)); 137 3446 mrj mdb_printf(" %%err = 0x%x\n", kregs[KREG_ERR]); 138 0 stevel } 139 170 sherrym 140 170 sherrym /* 141 170 sherrym * Sun Studio 10 patch compiler and gcc 3.4.3 Sun branch implemented a 142 170 sherrym * "-save_args" option on amd64. When the option is specified, INTEGER 143 170 sherrym * type function arguments passed via registers will be saved on the stack 144 170 sherrym * immediately after %rbp, and will not be modified through out the life 145 170 sherrym * of the routine. 146 170 sherrym * 147 170 sherrym * +--------+ 148 170 sherrym * %rbp --> | %rbp | 149 170 sherrym * +--------+ 150 170 sherrym * -0x8(%rbp) | %rdi | 151 170 sherrym * +--------+ 152 170 sherrym * -0x10(%rbp) | %rsi | 153 170 sherrym * +--------+ 154 170 sherrym * -0x18(%rbp) | %rdx | 155 170 sherrym * +--------+ 156 170 sherrym * -0x20(%rbp) | %rcx | 157 170 sherrym * +--------+ 158 170 sherrym * -0x28(%rbp) | %r8 | 159 170 sherrym * +--------+ 160 170 sherrym * -0x30(%rbp) | %r9 | 161 170 sherrym * +--------+ 162 170 sherrym * 163 170 sherrym * 164 170 sherrym * For example, for the following function, 165 170 sherrym * 166 170 sherrym * void 167 170 sherrym * foo(int a1, int a2, int a3, int a4, int a5, int a6, int a7) 168 170 sherrym * { 169 170 sherrym * ... 170 170 sherrym * } 171 170 sherrym * 172 170 sherrym * Disassembled code will look something like the following: 173 170 sherrym * 174 170 sherrym * pushq %rbp 175 170 sherrym * movq %rsp, %rbp 176 170 sherrym * subq $imm8, %rsp ** 177 170 sherrym * movq %rdi, -0x8(%rbp) 178 170 sherrym * movq %rsi, -0x10(%rbp) 179 170 sherrym * movq %rdx, -0x18(%rbp) 180 170 sherrym * movq %rcx, -0x20(%rbp) 181 170 sherrym * movq %r8, -0x28(%rbp) 182 170 sherrym * movq %r9, -0x30(%rbp) 183 170 sherrym * ... 184 170 sherrym * or 185 170 sherrym * pushq %rbp 186 170 sherrym * movq %rsp, %rbp 187 170 sherrym * subq $imm8, %rsp ** 188 170 sherrym * movq %r9, -0x30(%rbp) 189 170 sherrym * movq %r8, -0x28(%rbp) 190 170 sherrym * movq %rcx, -0x20(%rbp) 191 170 sherrym * movq %rdx, -0x18(%rbp) 192 170 sherrym * movq %rsi, -0x10(%rbp) 193 170 sherrym * movq %rdi, -0x8(%rbp) 194 170 sherrym * ... 195 170 sherrym * 196 170 sherrym * **: The space being reserved is in addition to what the current 197 170 sherrym * function prolog already reserves. 198 170 sherrym * 199 170 sherrym * If there are odd number of arguments to a function, additional space is 200 170 sherrym * reserved on the stack to maintain 16-byte alignment. For example, 201 170 sherrym * 202 170 sherrym * argc == 0: no argument saving. 203 170 sherrym * argc == 3: save 3, but space for 4 is reserved 204 170 sherrym * argc == 7: save 6. 205 170 sherrym */ 206 170 sherrym 207 170 sherrym /* 208 170 sherrym * The longest instruction sequence in bytes before all 6 arguments are 209 170 sherrym * saved on the stack. This value depends on compiler implementation, 210 170 sherrym * therefore it should be examined periodically to guarantee accuracy. 211 170 sherrym */ 212 170 sherrym #define SEQ_LEN 80 213 170 sherrym 214 170 sherrym /* 215 170 sherrym * Size of the instruction sequence arrays. It should correspond to 216 170 sherrym * the maximum number of arguments passed via registers. 217 170 sherrym */ 218 170 sherrym #define INSTR_ARRAY_SIZE 6 219 170 sherrym 220 170 sherrym #define INSTR4(ins, off) \ 221 170 sherrym (ins[(off)] + (ins[(off) + 1] << 8) + (ins[(off + 2)] << 16) + \ 222 170 sherrym (ins[(off) + 3] << 24)) 223 170 sherrym 224 170 sherrym /* 225 170 sherrym * Sun Studio 10 patch implementation saves %rdi first; 226 170 sherrym * GCC 3.4.3 Sun branch implementation saves them in reverse order. 227 170 sherrym */ 228 170 sherrym static const uint32_t save_instr[INSTR_ARRAY_SIZE] = { 229 170 sherrym 0xf87d8948, /* movq %rdi, -0x8(%rbp) */ 230 170 sherrym 0xf0758948, /* movq %rsi, -0x10(%rbp) */ 231 170 sherrym 0xe8558948, /* movq %rdx, -0x18(%rbp) */ 232 170 sherrym 0xe04d8948, /* movq %rcx, -0x20(%rbp) */ 233 170 sherrym 0xd845894c, /* movq %r8, -0x28(%rbp) */ 234 170 sherrym 0xd04d894c /* movq %r9, -0x30(%rbp) */ 235 170 sherrym }; 236 170 sherrym 237 275 sherrym static const uint32_t save_fp_instr[] = { 238 170 sherrym 0xe5894855, /* pushq %rbp; movq %rsp,%rbp, encoding 1 */ 239 275 sherrym 0xec8b4855, /* pushq %rbp; movq %rsp,%rbp, encoding 2 */ 240 275 sherrym 0xe58948cc, /* int $0x3; movq %rsp,%rbp, encoding 1 */ 241 275 sherrym 0xec8b48cc, /* int $0x3; movq %rsp,%rbp, encoding 2 */ 242 275 sherrym NULL 243 170 sherrym }; 244 170 sherrym 245 170 sherrym /* 246 170 sherrym * Look for the above instruction sequences as indicators for register 247 170 sherrym * arguments being available on the stack. 248 170 sherrym */ 249 170 sherrym static int 250 170 sherrym is_argsaved(mdb_tgt_t *t, uintptr_t fstart, uint64_t size, uint_t argc, 251 170 sherrym int start_index) 252 170 sherrym { 253 170 sherrym uint8_t ins[SEQ_LEN]; 254 170 sherrym int i, j; 255 170 sherrym uint32_t n; 256 170 sherrym 257 170 sherrym size = MIN(size, SEQ_LEN); 258 170 sherrym argc = MIN((start_index + argc), INSTR_ARRAY_SIZE); 259 170 sherrym 260 170 sherrym if (mdb_tgt_vread(t, ins, size, fstart) != size) 261 170 sherrym return (0); 262 170 sherrym 263 170 sherrym /* 264 170 sherrym * Make sure framepointer has been saved. 265 170 sherrym */ 266 170 sherrym n = INSTR4(ins, 0); 267 275 sherrym for (i = 0; save_fp_instr[i] != NULL; i++) { 268 170 sherrym if (n == save_fp_instr[i]) 269 170 sherrym break; 270 170 sherrym } 271 170 sherrym 272 275 sherrym if (save_fp_instr[i] == NULL) 273 170 sherrym return (0); 274 170 sherrym 275 170 sherrym /* 276 170 sherrym * Compare against Sun Studio implementation 277 170 sherrym */ 278 170 sherrym for (i = 8, j = start_index; i < size - 4; i++) { 279 170 sherrym n = INSTR4(ins, i); 280 170 sherrym 281 170 sherrym if (n == save_instr[j]) { 282 170 sherrym i += 3; 283 170 sherrym if (++j >= argc) 284 170 sherrym return (1); 285 170 sherrym } 286 170 sherrym } 287 170 sherrym 288 170 sherrym /* 289 170 sherrym * Compare against GCC implementation 290 170 sherrym */ 291 170 sherrym for (i = 8, j = argc - 1; i < size - 4; i++) { 292 170 sherrym n = INSTR4(ins, i); 293 170 sherrym 294 170 sherrym if (n == save_instr[j]) { 295 170 sherrym i += 3; 296 170 sherrym if (--j < start_index) 297 170 sherrym return (1); 298 170 sherrym } 299 170 sherrym } 300 170 sherrym 301 170 sherrym return (0); 302 170 sherrym } 303 170 sherrym 304 5084 johnlev /* 305 5084 johnlev * We expect all proper Solaris core files to have STACK_ALIGN-aligned stacks. 306 5084 johnlev * Hence the name. However, if the core file resulted from a 307 5084 johnlev * hypervisor-initiated panic, the hypervisor's frames may only be 64-bit 308 5084 johnlev * aligned instead of 128. 309 5084 johnlev */ 310 5084 johnlev static int 311 5084 johnlev fp_is_aligned(uintptr_t fp, int xpv_panic) 312 5084 johnlev { 313 5084 johnlev if (!xpv_panic && (fp & (STACK_ALIGN -1))) 314 5084 johnlev return (0); 315 5084 johnlev if ((fp & sizeof (uintptr_t) - 1)) 316 5084 johnlev return (0); 317 5084 johnlev return (1); 318 5084 johnlev } 319 5084 johnlev 320 0 stevel int 321 0 stevel mdb_amd64_kvm_stack_iter(mdb_tgt_t *t, const mdb_tgt_gregset_t *gsp, 322 0 stevel mdb_tgt_stack_f *func, void *arg) 323 0 stevel { 324 0 stevel mdb_tgt_gregset_t gregs; 325 0 stevel kreg_t *kregs = &gregs.kregs[0]; 326 0 stevel int got_pc = (gsp->kregs[KREG_RIP] != 0); 327 170 sherrym uint_t argc, reg_argc; 328 170 sherrym long fr_argv[32]; 329 170 sherrym int start_index; /* index to save_instr where to start comparison */ 330 170 sherrym int i; 331 0 stevel 332 0 stevel struct { 333 0 stevel uintptr_t fr_savfp; 334 0 stevel uintptr_t fr_savpc; 335 0 stevel } fr; 336 0 stevel 337 0 stevel uintptr_t fp = gsp->kregs[KREG_RBP]; 338 0 stevel uintptr_t pc = gsp->kregs[KREG_RIP]; 339 5084 johnlev uintptr_t lastfp, curpc; 340 170 sherrym 341 170 sherrym ssize_t size; 342 170 sherrym 343 170 sherrym GElf_Sym s; 344 170 sherrym mdb_syminfo_t sip; 345 170 sherrym mdb_ctf_funcinfo_t mfp; 346 5084 johnlev int xpv_panic = 0; 347 5084 johnlev #ifndef _KMDB 348 5084 johnlev int xp; 349 5084 johnlev 350 5084 johnlev if ((mdb_readsym(&xp, sizeof (xp), "xpv_panicking") != -1) && (xp > 0)) 351 5084 johnlev xpv_panic = 1; 352 5084 johnlev #endif 353 0 stevel 354 0 stevel bcopy(gsp, &gregs, sizeof (gregs)); 355 0 stevel 356 0 stevel while (fp != 0) { 357 0 stevel 358 170 sherrym curpc = pc; 359 170 sherrym 360 5084 johnlev if (!fp_is_aligned(fp, xpv_panic)) 361 0 stevel return (set_errno(EMDB_STKALIGN)); 362 0 stevel 363 170 sherrym if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) != sizeof (fr)) 364 170 sherrym return (-1); /* errno has been set for us */ 365 0 stevel 366 170 sherrym if ((mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY, 367 170 sherrym NULL, 0, &s, &sip) == 0) && 368 170 sherrym (mdb_ctf_func_info(&s, &sip, &mfp) == 0)) { 369 170 sherrym int return_type = mdb_ctf_type_kind(mfp.mtf_return); 370 170 sherrym argc = mfp.mtf_argc; 371 170 sherrym /* 372 170 sherrym * If the function returns a structure or union, 373 170 sherrym * %rdi contains the address in which to store the 374 170 sherrym * return value rather than for an argument. 375 170 sherrym */ 376 170 sherrym if (return_type == CTF_K_STRUCT || 377 170 sherrym return_type == CTF_K_UNION) 378 170 sherrym start_index = 1; 379 170 sherrym else 380 170 sherrym start_index = 0; 381 170 sherrym } else { 382 170 sherrym argc = 0; 383 170 sherrym } 384 170 sherrym 385 170 sherrym if (argc != 0 && is_argsaved(t, s.st_value, s.st_size, 386 170 sherrym argc, start_index)) { 387 170 sherrym 388 170 sherrym /* Upto to 6 arguments are passed via registers */ 389 170 sherrym reg_argc = MIN(6, mfp.mtf_argc); 390 170 sherrym size = reg_argc * sizeof (long); 391 170 sherrym 392 170 sherrym if (mdb_tgt_vread(t, fr_argv, size, (fp - size)) 393 170 sherrym != size) 394 170 sherrym return (-1); /* errno has been set for us */ 395 170 sherrym 396 170 sherrym /* 397 170 sherrym * Arrange the arguments in the right order for 398 170 sherrym * printing. 399 170 sherrym */ 400 170 sherrym for (i = 0; i < (reg_argc >> 1); i++) { 401 170 sherrym long t = fr_argv[i]; 402 170 sherrym 403 170 sherrym fr_argv[i] = fr_argv[reg_argc - i - 1]; 404 170 sherrym fr_argv[reg_argc - i - 1] = t; 405 170 sherrym } 406 170 sherrym 407 170 sherrym if (argc > 6) { 408 170 sherrym size = (argc - 6) * sizeof (long); 409 170 sherrym if (mdb_tgt_vread(t, &fr_argv[6], size, 410 170 sherrym fp + sizeof (fr)) != size) 411 170 sherrym return (-1); /* errno has been set */ 412 170 sherrym } 413 170 sherrym } else 414 170 sherrym argc = 0; 415 170 sherrym 416 170 sherrym if (got_pc && func(arg, pc, argc, fr_argv, &gregs) != 0) 417 0 stevel break; 418 0 stevel 419 0 stevel kregs[KREG_RSP] = kregs[KREG_RBP]; 420 0 stevel 421 5084 johnlev lastfp = fp; 422 5084 johnlev fp = fr.fr_savfp; 423 5084 johnlev /* 424 5084 johnlev * The Xen hypervisor marks a stack frame as belonging to 425 5084 johnlev * an exception by inverting the bits of the pointer to 426 5084 johnlev * that frame. We attempt to identify these frames by 427 5084 johnlev * inverting the pointer and seeing if it is within 0xfff 428 5084 johnlev * bytes of the last frame. 429 5084 johnlev */ 430 5084 johnlev if (xpv_panic) 431 5084 johnlev if ((fp != 0) && (fp < lastfp) && 432 5084 johnlev ((lastfp ^ ~fp) < 0xfff)) 433 5084 johnlev fp = ~fp; 434 5084 johnlev 435 5084 johnlev kregs[KREG_RBP] = fp; 436 0 stevel kregs[KREG_RIP] = pc = fr.fr_savpc; 437 170 sherrym 438 170 sherrym if (curpc == pc) 439 170 sherrym break; 440 0 stevel 441 0 stevel got_pc = (pc != 0); 442 0 stevel } 443 0 stevel 444 0 stevel return (0); 445 0 stevel } 446 0 stevel 447 0 stevel /* 448 0 stevel * Determine the return address for the current frame. Typically this is the 449 0 stevel * fr_savpc value from the current frame, but we also perform some special 450 0 stevel * handling to see if we are stopped on one of the first two instructions of 451 0 stevel * a typical function prologue, in which case %rbp will not be set up yet. 452 0 stevel */ 453 0 stevel int 454 0 stevel mdb_amd64_step_out(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, kreg_t fp, kreg_t sp, 455 0 stevel mdb_instr_t curinstr) 456 0 stevel { 457 0 stevel struct frame fr; 458 0 stevel GElf_Sym s; 459 0 stevel char buf[1]; 460 0 stevel 461 0 stevel enum { 462 0 stevel M_PUSHQ_RBP = 0x55, /* pushq %rbp */ 463 0 stevel M_REX_W = 0x48, /* REX prefix with only W set */ 464 0 stevel M_MOVL_RBP = 0x8b /* movq %rsp, %rbp with prefix */ 465 0 stevel }; 466 0 stevel 467 0 stevel if (mdb_tgt_lookup_by_addr(t, pc, MDB_TGT_SYM_FUZZY, 468 0 stevel buf, 0, &s, NULL) == 0) { 469 0 stevel if (pc == s.st_value && curinstr == M_PUSHQ_RBP) 470 0 stevel fp = sp - 8; 471 0 stevel else if (pc == s.st_value + 1 && curinstr == M_REX_W) { 472 0 stevel if (mdb_tgt_vread(t, &curinstr, sizeof (curinstr), 473 0 stevel pc + 1) == sizeof (curinstr) && curinstr == 474 0 stevel M_MOVL_RBP) 475 0 stevel fp = sp; 476 0 stevel } 477 0 stevel } 478 0 stevel 479 0 stevel if (mdb_tgt_vread(t, &fr, sizeof (fr), fp) == sizeof (fr)) { 480 0 stevel *p = fr.fr_savpc; 481 0 stevel return (0); 482 0 stevel } 483 0 stevel 484 0 stevel return (-1); /* errno is set for us */ 485 0 stevel } 486 0 stevel 487 0 stevel /*ARGSUSED*/ 488 0 stevel int 489 0 stevel mdb_amd64_next(mdb_tgt_t *t, uintptr_t *p, kreg_t pc, mdb_instr_t curinstr) 490 0 stevel { 491 0 stevel mdb_tgt_addr_t npc; 492 2244 dmick mdb_tgt_addr_t callpc; 493 0 stevel 494 0 stevel enum { 495 0 stevel M_CALL_REL = 0xe8, /* call near with relative displacement */ 496 0 stevel M_CALL_REG = 0xff, /* call near indirect or call far register */ 497 0 stevel 498 0 stevel M_REX_LO = 0x40, 499 0 stevel M_REX_HI = 0x4f 500 0 stevel }; 501 0 stevel 502 0 stevel /* 503 0 stevel * If the opcode is a near call with relative displacement, assume the 504 0 stevel * displacement is a rel32 from the next instruction. 505 0 stevel */ 506 0 stevel if (curinstr == M_CALL_REL) { 507 0 stevel *p = pc + sizeof (mdb_instr_t) + sizeof (uint32_t); 508 0 stevel return (0); 509 0 stevel } 510 0 stevel 511 0 stevel /* Skip the rex prefix, if any */ 512 2244 dmick callpc = pc; 513 2244 dmick while (curinstr >= M_REX_LO && curinstr <= M_REX_HI) { 514 2244 dmick if (mdb_tgt_vread(t, &curinstr, sizeof (curinstr), ++callpc) != 515 2244 dmick sizeof (curinstr)) 516 2244 dmick return (-1); /* errno is set for us */ 517 2244 dmick } 518 0 stevel 519 0 stevel if (curinstr != M_CALL_REG) { 520 0 stevel /* It's not a call */ 521 0 stevel return (set_errno(EAGAIN)); 522 0 stevel } 523 0 stevel 524 0 stevel if ((npc = mdb_dis_nextins(mdb.m_disasm, t, MDB_TGT_AS_VIRT, pc)) == pc) 525 0 stevel return (-1); /* errno is set for us */ 526 0 stevel 527 0 stevel *p = npc; 528 0 stevel return (0); 529 0 stevel } 530 0 stevel 531 0 stevel /*ARGSUSED*/ 532 0 stevel int 533 0 stevel mdb_amd64_kvm_frame(void *arglim, uintptr_t pc, uint_t argc, const long *argv, 534 0 stevel const mdb_tgt_gregset_t *gregs) 535 0 stevel { 536 0 stevel argc = MIN(argc, (uintptr_t)arglim); 537 0 stevel mdb_printf("%a(", pc); 538 0 stevel 539 0 stevel if (argc != 0) { 540 0 stevel mdb_printf("%lr", *argv++); 541 0 stevel for (argc--; argc != 0; argc--) 542 0 stevel mdb_printf(", %lr", *argv++); 543 0 stevel } 544 0 stevel 545 0 stevel mdb_printf(")\n"); 546 0 stevel return (0); 547 0 stevel } 548 0 stevel 549 0 stevel int 550 0 stevel mdb_amd64_kvm_framev(void *arglim, uintptr_t pc, uint_t argc, const long *argv, 551 0 stevel const mdb_tgt_gregset_t *gregs) 552 0 stevel { 553 170 sherrym /* 554 170 sherrym * Historically adb limited stack trace argument display to a fixed- 555 170 sherrym * size number of arguments since no symbolic debugging info existed. 556 170 sherrym * On amd64 we can detect the true number of saved arguments so only 557 170 sherrym * respect an arglim of zero; otherwise display the entire argv[]. 558 170 sherrym */ 559 170 sherrym if (arglim == 0) 560 170 sherrym argc = 0; 561 170 sherrym 562 0 stevel mdb_printf("%0?lr %a(", gregs->kregs[KREG_RBP], pc); 563 0 stevel 564 0 stevel if (argc != 0) { 565 0 stevel mdb_printf("%lr", *argv++); 566 0 stevel for (argc--; argc != 0; argc--) 567 0 stevel mdb_printf(", %lr", *argv++); 568 0 stevel } 569 0 stevel 570 0 stevel mdb_printf(")\n"); 571 0 stevel return (0); 572 0 stevel } 573