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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 /* 27 * Copyright 2015 Joyent, Inc. 28 */ 29 30 /* 31 * User Process Target Intel 32-bit component 32 * 33 * This file provides the ISA-dependent portion of the user process target. 34 * For more details on the implementation refer to mdb_proc.c. 35 */ 36 37 #include <mdb/mdb_proc.h> 38 #include <mdb/mdb_kreg.h> 39 #include <mdb/mdb_err.h> 40 #include <mdb/mdb_amd64util.h> 41 #include <mdb/mdb.h> 42 43 #include <sys/ucontext.h> 44 #include <sys/frame.h> 45 #include <libproc.h> 46 #include <sys/fp.h> 47 #include <ieeefp.h> 48 49 #include <stddef.h> 50 51 const mdb_tgt_regdesc_t pt_regdesc[] = { 52 { "r15", REG_R15, MDB_TGT_R_EXPORT }, 53 { "r15d", REG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 54 { "r15w", REG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 55 { "r15l", REG_R15, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 56 { "r14", REG_R14, MDB_TGT_R_EXPORT }, 57 { "r14d", REG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 58 { "r14w", REG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 59 { "r14l", REG_R14, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 60 { "r13", REG_R13, MDB_TGT_R_EXPORT }, 61 { "r13d", REG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 62 { "r13w", REG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 63 { "r13l", REG_R13, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 64 { "r12", REG_R12, MDB_TGT_R_EXPORT }, 65 { "r12d", REG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 66 { "r12w", REG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 67 { "r12l", REG_R12, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 68 { "r11", REG_R11, MDB_TGT_R_EXPORT }, 69 { "r11d", REG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 70 { "r11w", REG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 71 { "r11l", REG_R11, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 72 { "r10", REG_R10, MDB_TGT_R_EXPORT }, 73 { "r10d", REG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 74 { "r10w", REG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 75 { "r10l", REG_R10, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 76 { "r9", REG_R9, MDB_TGT_R_EXPORT }, 77 { "r9d", REG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 78 { "r9w", REG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 79 { "r9l", REG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 80 { "r8", REG_R8, MDB_TGT_R_EXPORT }, 81 { "r8d", REG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 82 { "r8w", REG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 83 { "r8l", REG_R8, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 84 { "rdi", REG_RDI, MDB_TGT_R_EXPORT }, 85 { "edi", REG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 86 { "di", REG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 87 { "dil", REG_RDI, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 88 { "rsi", REG_RSI, MDB_TGT_R_EXPORT }, 89 { "esi", REG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 90 { "si", REG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 91 { "sil", REG_RSI, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 92 { "rbp", REG_RBP, MDB_TGT_R_EXPORT }, 93 { "ebp", REG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 94 { "bp", REG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 95 { "bpl", REG_RBP, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 96 { "rbx", REG_RBX, MDB_TGT_R_EXPORT }, 97 { "ebx", REG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 98 { "bx", REG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 99 { "bh", REG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H }, 100 { "bl", REG_RBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 101 { "rdx", REG_RDX, MDB_TGT_R_EXPORT }, 102 { "edx", REG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 103 { "dx", REG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 104 { "dh", REG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H }, 105 { "dl", REG_RDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 106 { "rcx", REG_RCX, MDB_TGT_R_EXPORT }, 107 { "ecx", REG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 108 { "cx", REG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 109 { "ch", REG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H }, 110 { "cl", REG_RCX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 111 { "rax", REG_RAX, MDB_TGT_R_EXPORT }, 112 { "eax", REG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 113 { "ax", REG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 114 { "ah", REG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H }, 115 { "al", REG_RAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 116 { "trapno", REG_TRAPNO, MDB_TGT_R_EXPORT }, 117 { "err", REG_ERR, MDB_TGT_R_EXPORT }, 118 { "rip", REG_RIP, MDB_TGT_R_EXPORT }, 119 { "cs", REG_CS, MDB_TGT_R_EXPORT }, 120 { "rflags", REG_RFL, MDB_TGT_R_EXPORT }, 121 { "eflags", REG_RFL, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 122 { "rsp", REG_RSP, MDB_TGT_R_EXPORT }, 123 { "esp", REG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_32 }, 124 { "sp", REG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 125 { "spl", REG_RSP, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 126 { "ss", REG_SS, MDB_TGT_R_EXPORT }, 127 { "fs", REG_FS, MDB_TGT_R_EXPORT }, 128 { "gs", REG_GS, MDB_TGT_R_EXPORT }, 129 { "es", REG_ES, MDB_TGT_R_EXPORT }, 130 { "ds", REG_DS, MDB_TGT_R_EXPORT }, 131 { "fsbase", REG_FSBASE, MDB_TGT_R_EXPORT }, 132 { "gsbase", REG_GSBASE, MDB_TGT_R_EXPORT }, 133 { NULL, 0, 0 } 134 }; 135 136 /* 137 * We cannot rely on pr_instr, because if we hit a breakpoint or the user has 138 * artifically modified memory, it will no longer be correct. 139 */ 140 static uint8_t 141 pt_read_instr(mdb_tgt_t *t) 142 { 143 const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 144 uint8_t ret = 0; 145 146 (void) mdb_tgt_vread(t, &ret, sizeof (ret), psp->pr_reg[REG_RIP]); 147 148 return (ret); 149 } 150 151 /*ARGSUSED*/ 152 int 153 pt_regs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 154 { 155 mdb_tgt_t *t = mdb.m_target; 156 mdb_tgt_tid_t tid; 157 prgregset_t grs; 158 prgreg_t rflags; 159 boolean_t from_ucontext = B_FALSE; 160 161 if (mdb_getopts(argc, argv, 162 'u', MDB_OPT_SETBITS, B_TRUE, &from_ucontext, NULL) != argc) { 163 return (DCMD_USAGE); 164 } 165 166 if (from_ucontext) { 167 int off; 168 int o0, o1; 169 170 if (!(flags & DCMD_ADDRSPEC)) { 171 mdb_warn("-u requires a ucontext_t address\n"); 172 return (DCMD_ERR); 173 } 174 175 o0 = mdb_ctf_offsetof_by_name("ucontext_t", "uc_mcontext"); 176 o1 = mdb_ctf_offsetof_by_name("mcontext_t", "gregs"); 177 if (o0 == -1 || o1 == -1) { 178 off = offsetof(ucontext_t, uc_mcontext) + 179 offsetof(mcontext_t, gregs); 180 } else { 181 off = o0 + o1; 182 } 183 184 if (mdb_vread(&grs, sizeof (grs), addr + off) != sizeof (grs)) { 185 mdb_warn("failed to read from ucontext_t %p", addr); 186 return (DCMD_ERR); 187 } 188 goto print_regs; 189 } 190 191 if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_UNDEAD) { 192 mdb_warn("no process active\n"); 193 return (DCMD_ERR); 194 } 195 196 if (Pstate(t->t_pshandle) == PS_LOST) { 197 mdb_warn("debugger has lost control of process\n"); 198 return (DCMD_ERR); 199 } 200 201 if (flags & DCMD_ADDRSPEC) 202 tid = (mdb_tgt_tid_t)addr; 203 else 204 tid = PTL_TID(t); 205 206 if (PTL_GETREGS(t, tid, grs) != 0) { 207 mdb_warn("failed to get current register set"); 208 return (DCMD_ERR); 209 } 210 211 print_regs: 212 rflags = grs[REG_RFL]; 213 214 mdb_printf("%%rax = 0x%0?p\t%%r8 = 0x%0?p\n", 215 grs[REG_RAX], grs[REG_R8]); 216 mdb_printf("%%rbx = 0x%0?p\t%%r9 = 0x%0?p\n", 217 grs[REG_RBX], grs[REG_R9]); 218 mdb_printf("%%rcx = 0x%0?p\t%%r10 = 0x%0?p\n", 219 grs[REG_RCX], grs[REG_R10]); 220 mdb_printf("%%rdx = 0x%0?p\t%%r11 = 0x%0?p\n", 221 grs[REG_RDX], grs[REG_R11]); 222 mdb_printf("%%rsi = 0x%0?p\t%%r12 = 0x%0?p\n", 223 grs[REG_RSI], grs[REG_R12]); 224 mdb_printf("%%rdi = 0x%0?p\t%%r13 = 0x%0?p\n", 225 grs[REG_RDI], grs[REG_R13]); 226 mdb_printf(" %?s\t%%r14 = 0x%0?p\n", 227 "", grs[REG_R14]); 228 mdb_printf(" %?s\t%%r15 = 0x%0?p\n", 229 "", grs[REG_R15]); 230 231 mdb_printf("\n"); 232 233 mdb_printf("%%cs = 0x%04x\t%%fs = 0x%04x\t%%gs = 0x%04x\n", 234 grs[REG_CS], grs[REG_FS], grs[REG_GS]); 235 mdb_printf("%%ds = 0x%04x\t%%es = 0x%04x\t%%ss = 0x%04x\n", 236 grs[REG_DS], grs[REG_ES], grs[REG_SS]); 237 238 mdb_printf("\n"); 239 240 mdb_printf("%%rip = 0x%0?p %A\n", grs[REG_RIP], grs[REG_RIP]); 241 mdb_printf("%%rbp = 0x%0?p\n", grs[REG_RBP], grs[REG_RBP]); 242 mdb_printf("%%rsp = 0x%0?p\n", grs[REG_RSP], grs[REG_RSP]); 243 244 mdb_printf("\n"); 245 246 mdb_printf("%%rflags = 0x%08x\n", rflags); 247 248 mdb_printf(" id=%u vip=%u vif=%u ac=%u vm=%u rf=%u nt=%u iopl=0x%x\n", 249 (rflags & KREG_EFLAGS_ID_MASK) >> KREG_EFLAGS_ID_SHIFT, 250 (rflags & KREG_EFLAGS_VIP_MASK) >> KREG_EFLAGS_VIP_SHIFT, 251 (rflags & KREG_EFLAGS_VIF_MASK) >> KREG_EFLAGS_VIF_SHIFT, 252 (rflags & KREG_EFLAGS_AC_MASK) >> KREG_EFLAGS_AC_SHIFT, 253 (rflags & KREG_EFLAGS_VM_MASK) >> KREG_EFLAGS_VM_SHIFT, 254 (rflags & KREG_EFLAGS_RF_MASK) >> KREG_EFLAGS_RF_SHIFT, 255 (rflags & KREG_EFLAGS_NT_MASK) >> KREG_EFLAGS_NT_SHIFT, 256 (rflags & KREG_EFLAGS_IOPL_MASK) >> KREG_EFLAGS_IOPL_SHIFT); 257 258 mdb_printf(" status=<%s,%s,%s,%s,%s,%s,%s,%s,%s>\n", 259 (rflags & KREG_EFLAGS_OF_MASK) ? "OF" : "of", 260 (rflags & KREG_EFLAGS_DF_MASK) ? "DF" : "df", 261 (rflags & KREG_EFLAGS_IF_MASK) ? "IF" : "if", 262 (rflags & KREG_EFLAGS_TF_MASK) ? "TF" : "tf", 263 (rflags & KREG_EFLAGS_SF_MASK) ? "SF" : "sf", 264 (rflags & KREG_EFLAGS_ZF_MASK) ? "ZF" : "zf", 265 (rflags & KREG_EFLAGS_AF_MASK) ? "AF" : "af", 266 (rflags & KREG_EFLAGS_PF_MASK) ? "PF" : "pf", 267 (rflags & KREG_EFLAGS_CF_MASK) ? "CF" : "cf"); 268 269 mdb_printf("\n"); 270 271 mdb_printf("%%gsbase = 0x%0?p\n", grs[REG_GSBASE]); 272 mdb_printf("%%fsbase = 0x%0?p\n", grs[REG_FSBASE]); 273 mdb_printf("%%trapno = 0x%x\n", grs[REG_TRAPNO]); 274 mdb_printf(" %%err = 0x%x\n", grs[REG_ERR]); 275 276 return (set_errno(ENOTSUP)); 277 } 278 279 static const char * 280 fpcw2str(uint32_t cw, char *buf, size_t nbytes) 281 { 282 char *end = buf + nbytes; 283 char *p = buf; 284 285 buf[0] = '\0'; 286 287 /* 288 * Decode all masks in the 80387 control word. 289 */ 290 if (cw & FPIM) 291 p += mdb_snprintf(p, (size_t)(end - p), "|IM"); 292 if (cw & FPDM) 293 p += mdb_snprintf(p, (size_t)(end - p), "|DM"); 294 if (cw & FPZM) 295 p += mdb_snprintf(p, (size_t)(end - p), "|ZM"); 296 if (cw & FPOM) 297 p += mdb_snprintf(p, (size_t)(end - p), "|OM"); 298 if (cw & FPUM) 299 p += mdb_snprintf(p, (size_t)(end - p), "|UM"); 300 if (cw & FPPM) 301 p += mdb_snprintf(p, (size_t)(end - p), "|PM"); 302 if (cw & FPPC) 303 p += mdb_snprintf(p, (size_t)(end - p), "|PC"); 304 if (cw & FPRC) 305 p += mdb_snprintf(p, (size_t)(end - p), "|RC"); 306 if (cw & FPIC) 307 p += mdb_snprintf(p, (size_t)(end - p), "|IC"); 308 309 /* 310 * Decode precision, rounding, and infinity options in control word. 311 */ 312 if (cw & FPSIG24) 313 p += mdb_snprintf(p, (size_t)(end - p), "|SIG24"); 314 if (cw & FPSIG53) 315 p += mdb_snprintf(p, (size_t)(end - p), "|SIG53"); 316 if (cw & FPSIG64) 317 p += mdb_snprintf(p, (size_t)(end - p), "|SIG64"); 318 319 if ((cw & FPRC) == (FPRD|FPRU)) 320 p += mdb_snprintf(p, (size_t)(end - p), "|RTZ"); 321 else if (cw & FPRD) 322 p += mdb_snprintf(p, (size_t)(end - p), "|RD"); 323 else if (cw & FPRU) 324 p += mdb_snprintf(p, (size_t)(end - p), "|RU"); 325 else 326 p += mdb_snprintf(p, (size_t)(end - p), "|RTN"); 327 328 if (cw & FPA) 329 p += mdb_snprintf(p, (size_t)(end - p), "|A"); 330 else 331 p += mdb_snprintf(p, (size_t)(end - p), "|P"); 332 if (cw & WFPB17) 333 p += mdb_snprintf(p, (size_t)(end - p), "|WFPB17"); 334 if (cw & WFPB24) 335 p += mdb_snprintf(p, (size_t)(end - p), "|WFPB24"); 336 337 if (buf[0] == '|') 338 return (buf + 1); 339 340 return ("0"); 341 } 342 343 static const char * 344 fpsw2str(uint32_t cw, char *buf, size_t nbytes) 345 { 346 char *end = buf + nbytes; 347 char *p = buf; 348 349 buf[0] = '\0'; 350 351 /* 352 * Decode all masks in the 80387 status word. 353 */ 354 if (cw & FPS_IE) 355 p += mdb_snprintf(p, (size_t)(end - p), "|IE"); 356 if (cw & FPS_DE) 357 p += mdb_snprintf(p, (size_t)(end - p), "|DE"); 358 if (cw & FPS_ZE) 359 p += mdb_snprintf(p, (size_t)(end - p), "|ZE"); 360 if (cw & FPS_OE) 361 p += mdb_snprintf(p, (size_t)(end - p), "|OE"); 362 if (cw & FPS_UE) 363 p += mdb_snprintf(p, (size_t)(end - p), "|UE"); 364 if (cw & FPS_PE) 365 p += mdb_snprintf(p, (size_t)(end - p), "|PE"); 366 if (cw & FPS_SF) 367 p += mdb_snprintf(p, (size_t)(end - p), "|SF"); 368 if (cw & FPS_ES) 369 p += mdb_snprintf(p, (size_t)(end - p), "|ES"); 370 if (cw & FPS_C0) 371 p += mdb_snprintf(p, (size_t)(end - p), "|C0"); 372 if (cw & FPS_C1) 373 p += mdb_snprintf(p, (size_t)(end - p), "|C1"); 374 if (cw & FPS_C2) 375 p += mdb_snprintf(p, (size_t)(end - p), "|C2"); 376 if (cw & FPS_C3) 377 p += mdb_snprintf(p, (size_t)(end - p), "|C3"); 378 if (cw & FPS_B) 379 p += mdb_snprintf(p, (size_t)(end - p), "|B"); 380 381 if (buf[0] == '|') 382 return (buf + 1); 383 384 return ("0"); 385 } 386 387 static const char * 388 fpmxcsr2str(uint32_t mxcsr, char *buf, size_t nbytes) 389 { 390 char *end = buf + nbytes; 391 char *p = buf; 392 393 buf[0] = '\0'; 394 395 /* 396 * Decode the MXCSR word 397 */ 398 if (mxcsr & SSE_IE) 399 p += mdb_snprintf(p, (size_t)(end - p), "|IE"); 400 if (mxcsr & SSE_DE) 401 p += mdb_snprintf(p, (size_t)(end - p), "|DE"); 402 if (mxcsr & SSE_ZE) 403 p += mdb_snprintf(p, (size_t)(end - p), "|ZE"); 404 if (mxcsr & SSE_OE) 405 p += mdb_snprintf(p, (size_t)(end - p), "|OE"); 406 if (mxcsr & SSE_UE) 407 p += mdb_snprintf(p, (size_t)(end - p), "|UE"); 408 if (mxcsr & SSE_PE) 409 p += mdb_snprintf(p, (size_t)(end - p), "|PE"); 410 411 if (mxcsr & SSE_DAZ) 412 p += mdb_snprintf(p, (size_t)(end - p), "|DAZ"); 413 414 if (mxcsr & SSE_IM) 415 p += mdb_snprintf(p, (size_t)(end - p), "|IM"); 416 if (mxcsr & SSE_DM) 417 p += mdb_snprintf(p, (size_t)(end - p), "|DM"); 418 if (mxcsr & SSE_ZM) 419 p += mdb_snprintf(p, (size_t)(end - p), "|ZM"); 420 if (mxcsr & SSE_OM) 421 p += mdb_snprintf(p, (size_t)(end - p), "|OM"); 422 if (mxcsr & SSE_UM) 423 p += mdb_snprintf(p, (size_t)(end - p), "|UM"); 424 if (mxcsr & SSE_PM) 425 p += mdb_snprintf(p, (size_t)(end - p), "|PM"); 426 427 if ((mxcsr & SSE_RC) == (SSE_RD|SSE_RU)) 428 p += mdb_snprintf(p, (size_t)(end - p), "|RTZ"); 429 else if (mxcsr & SSE_RD) 430 p += mdb_snprintf(p, (size_t)(end - p), "|RD"); 431 else if (mxcsr & SSE_RU) 432 p += mdb_snprintf(p, (size_t)(end - p), "|RU"); 433 else 434 p += mdb_snprintf(p, (size_t)(end - p), "|RTN"); 435 436 if (mxcsr & SSE_FZ) 437 p += mdb_snprintf(p, (size_t)(end - p), "|FZ"); 438 439 if (buf[0] == '|') 440 return (buf + 1); 441 return ("0"); 442 } 443 444 /*ARGSUSED*/ 445 int 446 pt_fpregs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 447 { 448 mdb_tgt_t *t = mdb.m_target; 449 mdb_tgt_tid_t tid; 450 prfpregset_t fprs; 451 struct _fpchip_state fps; 452 char buf[256]; 453 uint_t top; 454 int i; 455 456 /* 457 * Union for overlaying _fpreg structure on to quad-precision 458 * floating-point value (long double). 459 */ 460 union { 461 struct _fpreg reg; 462 long double ld; 463 } fpru; 464 465 /* 466 * Array of strings corresponding to FPU tag word values (see 467 * section 7.3.6 of the Intel Programmer's Reference Manual). 468 */ 469 const char *tag_strings[] = { "valid", "zero", "special", "empty" }; 470 471 if (argc != 0) 472 return (DCMD_USAGE); 473 474 if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_UNDEAD) { 475 mdb_warn("no process active\n"); 476 return (DCMD_ERR); 477 } 478 479 if (Pstate(t->t_pshandle) == PS_LOST) { 480 mdb_warn("debugger has lost control of process\n"); 481 return (DCMD_ERR); 482 } 483 484 if (flags & DCMD_ADDRSPEC) 485 tid = (mdb_tgt_tid_t)addr; 486 else 487 tid = PTL_TID(t); 488 489 mdb_printf("AMD64 (80486 chip with SSE)\n"); 490 491 if (PTL_GETFPREGS(t, tid, &fprs) != 0) { 492 mdb_warn("failed to get floating point registers"); 493 return (DCMD_ERR); 494 } 495 496 bcopy(&fprs.fp_reg_set.fpchip_state, &fps, sizeof (fps)); 497 498 fps.status &= 0xffff; /* saved status word is really 16 bits */ 499 500 mdb_printf("cw 0x%04x (%s)\n", fps.cw, 501 fpcw2str(fps.cw, buf, sizeof (buf))); 502 503 top = (fps.sw & FPS_TOP) >> 11; 504 mdb_printf("sw 0x%04x (TOP=0t%u) (%s)\n", fps.sw, 505 top, fpsw2str(fps.sw, buf, sizeof (buf))); 506 507 mdb_printf("xcp sw 0x%04x (%s)\n\n", fps.status, 508 fpsw2str(fps.status, buf, sizeof (buf))); 509 510 mdb_printf("fop 0x%x\n", fps.fop); 511 mdb_printf("rip 0x%x\n", fps.rip); 512 mdb_printf("rdp 0x%x\n\n", fps.rdp); 513 514 for (i = 0; i < 8; i++) { 515 /* 516 * Recall that we need to use the current TOP-of-stack value to 517 * associate the _st[] index back to a physical register number, 518 * since tag word indices are physical register numbers. Then 519 * to get the tag value, we shift over two bits for each tag 520 * index, and then grab the bottom two bits. 521 */ 522 uint_t tag_index = (i + top) & 7; 523 uint_t tag_fctw = (fps.fctw >> tag_index) & 1; 524 uint_t tag_value; 525 uint_t exp; 526 527 /* 528 * AMD64 stores the tag in a compressed form. It is 529 * necessary to extract the original 2-bit tag value. 530 * See AMD64 Architecture Programmer's Manual Volume 2: 531 * System Programming, Chapter 11. 532 */ 533 534 fpru.ld = fps.st[i].__fpr_pad._q; 535 exp = fpru.reg.exponent & 0x7fff; 536 537 if (tag_fctw == 0) { 538 tag_value = 3; /* empty */ 539 } else if (exp == 0) { 540 if (fpru.reg.significand[0] == 0 && 541 fpru.reg.significand[1] == 0 && 542 fpru.reg.significand[2] == 0 && 543 fpru.reg.significand[3] == 0) 544 tag_value = 1; /* zero */ 545 else 546 tag_value = 2; /* special: denormal */ 547 } else if (exp == 0x7fff) { 548 tag_value = 2; /* special: infinity or NaN */ 549 } else if (fpru.reg.significand[3] & 0x8000) { 550 tag_value = 0; /* valid */ 551 } else { 552 tag_value = 2; /* special: unnormal */ 553 } 554 555 mdb_printf("%%st%d 0x%04x.%04x%04x%04x%04x = %lg %s\n", 556 i, fpru.reg.exponent, 557 fpru.reg.significand[3], fpru.reg.significand[2], 558 fpru.reg.significand[1], fpru.reg.significand[0], 559 fpru.ld, tag_strings[tag_value]); 560 } 561 562 mdb_printf("\nmxcsr 0x%04x (%s)\n", fps.mxcsr, 563 fpmxcsr2str(fps.mxcsr, buf, sizeof (buf))); 564 mdb_printf("xcp 0x%04x (%s)\n\n", fps.xstatus, 565 fpmxcsr2str(fps.xstatus, buf, sizeof (buf))); 566 567 for (i = 0; i < 8; i++) 568 mdb_printf("%%xmm%d 0x%08x%08x%08x%08x\n", i, 569 fps.xmm[i]._l[3], fps.xmm[i]._l[2], 570 fps.xmm[i]._l[1], fps.xmm[i]._l[0]); 571 572 return (DCMD_OK); 573 } 574 575 /*ARGSUSED*/ 576 int 577 pt_getfpreg(mdb_tgt_t *t, mdb_tgt_tid_t tid, ushort_t rd_num, 578 ushort_t rd_flags, mdb_tgt_reg_t *rp) 579 { 580 return (set_errno(ENOTSUP)); 581 } 582 583 /*ARGSUSED*/ 584 int 585 pt_putfpreg(mdb_tgt_t *t, mdb_tgt_tid_t tid, ushort_t rd_num, 586 ushort_t rd_flags, mdb_tgt_reg_t rval) 587 { 588 return (set_errno(ENOTSUP)); 589 } 590 591 /*ARGSUSED*/ 592 void 593 pt_addfpregs(mdb_tgt_t *t) 594 { 595 /* not implemented */ 596 } 597 598 /*ARGSUSED*/ 599 int 600 pt_frameregs(void *arglim, uintptr_t pc, uint_t argc, const long *argv, 601 const mdb_tgt_gregset_t *gregs, boolean_t pc_faked) 602 { 603 return (set_errno(ENOTSUP)); 604 } 605 606 /*ARGSUSED*/ 607 const char * 608 pt_disasm(const GElf_Ehdr *ehp) 609 { 610 return ("amd64"); 611 } 612 613 /* 614 * Determine the return address for the current frame. 615 */ 616 int 617 pt_step_out(mdb_tgt_t *t, uintptr_t *p) 618 { 619 const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 620 621 if (Pstate(t->t_pshandle) != PS_STOP) 622 return (set_errno(EMDB_TGTBUSY)); 623 624 return (mdb_amd64_step_out(t, p, psp->pr_reg[EIP], psp->pr_reg[EBP], 625 psp->pr_reg[UESP], psp->pr_instr)); 626 } 627 628 /* 629 * Return the address of the next instruction following a call, or return -1 630 * and set errno to EAGAIN if the target should just single-step. 631 */ 632 int 633 pt_next(mdb_tgt_t *t, uintptr_t *p) 634 { 635 const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 636 637 if (Pstate(t->t_pshandle) != PS_STOP) 638 return (set_errno(EMDB_TGTBUSY)); 639 640 return (mdb_amd64_next(t, p, psp->pr_reg[REG_RIP], pt_read_instr(t))); 641 } 642