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 2019 Doma Gergő Mihály <doma.gergo.mihaly@gmail.com> 28 * Copyright 2018 Joyent, Inc. 29 */ 30 31 /* 32 * User Process Target Intel 32-bit component 33 * 34 * This file provides the ISA-dependent portion of the user process target. 35 * For more details on the implementation refer to mdb_proc.c. 36 */ 37 38 #include <mdb/mdb_proc.h> 39 #include <mdb/mdb_kreg.h> 40 #include <mdb/mdb_err.h> 41 #include <mdb/mdb_isautil.h> 42 #include <mdb/mdb_ia32util.h> 43 #include <mdb/mdb.h> 44 45 #include <sys/ucontext.h> 46 #include <sys/frame.h> 47 #include <libproc.h> 48 #include <sys/fp.h> 49 #include <ieeefp.h> 50 51 #include <stddef.h> 52 53 const mdb_tgt_regdesc_t pt_regdesc[] = { 54 { "gs", GS, MDB_TGT_R_EXPORT }, 55 { "fs", FS, MDB_TGT_R_EXPORT }, 56 { "es", ES, MDB_TGT_R_EXPORT }, 57 { "ds", DS, MDB_TGT_R_EXPORT }, 58 { "edi", EDI, MDB_TGT_R_EXPORT }, 59 { "di", EDI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 60 { "esi", ESI, MDB_TGT_R_EXPORT }, 61 { "si", ESI, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 62 { "ebp", EBP, MDB_TGT_R_EXPORT }, 63 { "bp", EBP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 64 { "kesp", ESP, MDB_TGT_R_EXPORT }, 65 { "ksp", ESP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 66 { "ebx", EBX, MDB_TGT_R_EXPORT }, 67 { "bx", EBX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 68 { "bh", EBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H }, 69 { "bl", EBX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 70 { "edx", EDX, MDB_TGT_R_EXPORT }, 71 { "dx", EDX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 72 { "dh", EDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H }, 73 { "dl", EDX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 74 { "ecx", ECX, MDB_TGT_R_EXPORT }, 75 { "cx", ECX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 76 { "ch", ECX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H }, 77 { "cl", ECX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 78 { "eax", EAX, MDB_TGT_R_EXPORT }, 79 { "ax", EAX, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 80 { "ah", EAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8H }, 81 { "al", EAX, MDB_TGT_R_EXPORT | MDB_TGT_R_8L }, 82 { "trapno", TRAPNO, MDB_TGT_R_EXPORT }, 83 { "err", ERR, MDB_TGT_R_EXPORT }, 84 { "eip", EIP, MDB_TGT_R_EXPORT }, 85 { "cs", CS, MDB_TGT_R_EXPORT }, 86 { "eflags", EFL, MDB_TGT_R_EXPORT }, 87 { "esp", UESP, MDB_TGT_R_EXPORT }, 88 { "sp", UESP, MDB_TGT_R_EXPORT | MDB_TGT_R_16 }, 89 { "ss", SS, MDB_TGT_R_EXPORT }, 90 { NULL, 0, 0 } 91 }; 92 93 /* 94 * We cannot rely on pr_instr, because if we hit a breakpoint or the user has 95 * artifically modified memory, it will no longer be correct. 96 */ 97 static uint8_t 98 pt_read_instr(mdb_tgt_t *t) 99 { 100 const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 101 uint8_t ret = 0; 102 103 (void) mdb_tgt_aread(t, MDB_TGT_AS_VIRT_I, &ret, sizeof (ret), 104 psp->pr_reg[EIP]); 105 106 return (ret); 107 } 108 109 /*ARGSUSED*/ 110 int 111 pt_regs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 112 { 113 mdb_tgt_t *t = mdb.m_target; 114 mdb_tgt_tid_t tid; 115 prgregset_t grs; 116 prgreg_t eflags; 117 boolean_t from_ucontext = B_FALSE; 118 119 if (mdb_getopts(argc, argv, 120 'u', MDB_OPT_SETBITS, B_TRUE, &from_ucontext, NULL) != argc) { 121 return (DCMD_USAGE); 122 } 123 124 if (from_ucontext) { 125 int off; 126 int o0, o1; 127 128 if (!(flags & DCMD_ADDRSPEC)) { 129 mdb_warn("-u requires a ucontext_t address\n"); 130 return (DCMD_ERR); 131 } 132 133 o0 = mdb_ctf_offsetof_by_name("ucontext_t", "uc_mcontext"); 134 o1 = mdb_ctf_offsetof_by_name("mcontext_t", "gregs"); 135 if (o0 == -1 || o1 == -1) { 136 off = offsetof(ucontext_t, uc_mcontext) + 137 offsetof(mcontext_t, gregs); 138 } else { 139 off = o0 + o1; 140 } 141 142 if (mdb_vread(&grs, sizeof (grs), addr + off) != sizeof (grs)) { 143 mdb_warn("failed to read from ucontext_t %p", addr); 144 return (DCMD_ERR); 145 } 146 goto print_regs; 147 } 148 149 if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_UNDEAD) { 150 mdb_warn("no process active\n"); 151 return (DCMD_ERR); 152 } 153 154 if (Pstate(t->t_pshandle) == PS_LOST) { 155 mdb_warn("debugger has lost control of process\n"); 156 return (DCMD_ERR); 157 } 158 159 if (flags & DCMD_ADDRSPEC) 160 tid = (mdb_tgt_tid_t)addr; 161 else 162 tid = PTL_TID(t); 163 164 if (PTL_GETREGS(t, tid, grs) != 0) { 165 mdb_warn("failed to get current register set"); 166 return (DCMD_ERR); 167 } 168 169 print_regs: 170 eflags = grs[EFL]; 171 172 mdb_printf("%%cs = 0x%04x\t\t%%eax = 0x%0?p %A\n", 173 grs[CS], grs[EAX], grs[EAX]); 174 175 mdb_printf("%%ds = 0x%04x\t\t%%ebx = 0x%0?p %A\n", 176 grs[DS], grs[EBX], grs[EBX]); 177 178 mdb_printf("%%ss = 0x%04x\t\t%%ecx = 0x%0?p %A\n", 179 grs[SS], grs[ECX], grs[ECX]); 180 181 mdb_printf("%%es = 0x%04x\t\t%%edx = 0x%0?p %A\n", 182 grs[ES], grs[EDX], grs[EDX]); 183 184 mdb_printf("%%fs = 0x%04x\t\t%%esi = 0x%0?p %A\n", 185 grs[FS], grs[ESI], grs[ESI]); 186 187 mdb_printf("%%gs = 0x%04x\t\t%%edi = 0x%0?p %A\n\n", 188 grs[GS], grs[EDI], grs[EDI]); 189 190 mdb_printf(" %%eip = 0x%0?p %A\n", grs[EIP], grs[EIP]); 191 mdb_printf(" %%ebp = 0x%0?p\n", grs[EBP]); 192 mdb_printf("%%kesp = 0x%0?p\n\n", grs[ESP]); 193 mdb_printf("%%eflags = 0x%08x\n", eflags); 194 195 mdb_printf(" id=%u vip=%u vif=%u ac=%u vm=%u rf=%u nt=%u iopl=0x%x\n", 196 (eflags & KREG_EFLAGS_ID_MASK) >> KREG_EFLAGS_ID_SHIFT, 197 (eflags & KREG_EFLAGS_VIP_MASK) >> KREG_EFLAGS_VIP_SHIFT, 198 (eflags & KREG_EFLAGS_VIF_MASK) >> KREG_EFLAGS_VIF_SHIFT, 199 (eflags & KREG_EFLAGS_AC_MASK) >> KREG_EFLAGS_AC_SHIFT, 200 (eflags & KREG_EFLAGS_VM_MASK) >> KREG_EFLAGS_VM_SHIFT, 201 (eflags & KREG_EFLAGS_RF_MASK) >> KREG_EFLAGS_RF_SHIFT, 202 (eflags & KREG_EFLAGS_NT_MASK) >> KREG_EFLAGS_NT_SHIFT, 203 (eflags & KREG_EFLAGS_IOPL_MASK) >> KREG_EFLAGS_IOPL_SHIFT); 204 205 mdb_printf(" status=<%s,%s,%s,%s,%s,%s,%s,%s,%s>\n\n", 206 (eflags & KREG_EFLAGS_OF_MASK) ? "OF" : "of", 207 (eflags & KREG_EFLAGS_DF_MASK) ? "DF" : "df", 208 (eflags & KREG_EFLAGS_IF_MASK) ? "IF" : "if", 209 (eflags & KREG_EFLAGS_TF_MASK) ? "TF" : "tf", 210 (eflags & KREG_EFLAGS_SF_MASK) ? "SF" : "sf", 211 (eflags & KREG_EFLAGS_ZF_MASK) ? "ZF" : "zf", 212 (eflags & KREG_EFLAGS_AF_MASK) ? "AF" : "af", 213 (eflags & KREG_EFLAGS_PF_MASK) ? "PF" : "pf", 214 (eflags & KREG_EFLAGS_CF_MASK) ? "CF" : "cf"); 215 216 mdb_printf(" %%esp = 0x%0?x\n", grs[UESP]); 217 mdb_printf("%%trapno = 0x%x\n", grs[TRAPNO]); 218 mdb_printf(" %%err = 0x%x\n", grs[ERR]); 219 220 return (DCMD_OK); 221 } 222 223 static const char * 224 fpcw2str(uint32_t cw, char *buf, size_t nbytes) 225 { 226 char *end = buf + nbytes; 227 char *p = buf; 228 229 buf[0] = '\0'; 230 231 /* 232 * Decode all exception masks in the x87 FPU Control Word. 233 * 234 * See here: 235 * Intel® 64 and IA-32 Architectures Software Developer’s Manual, 236 * Volume 1: Basic Architecture, 8.1.5 x87 FPU Control Word 237 */ 238 if (cw & FPIM) /* Invalid operation mask. */ 239 p += mdb_snprintf(p, (size_t)(end - p), "|IM"); 240 if (cw & FPDM) /* Denormalized operand mask. */ 241 p += mdb_snprintf(p, (size_t)(end - p), "|DM"); 242 if (cw & FPZM) /* Zero divide mask. */ 243 p += mdb_snprintf(p, (size_t)(end - p), "|ZM"); 244 if (cw & FPOM) /* Overflow mask. */ 245 p += mdb_snprintf(p, (size_t)(end - p), "|OM"); 246 if (cw & FPUM) /* Underflow mask. */ 247 p += mdb_snprintf(p, (size_t)(end - p), "|UM"); 248 if (cw & FPPM) /* Precision mask. */ 249 p += mdb_snprintf(p, (size_t)(end - p), "|PM"); 250 251 /* 252 * Decode precision control options. 253 */ 254 switch (cw & FPPC) { 255 case FPSIG24: 256 /* 24-bit significand, single precision. */ 257 p += mdb_snprintf(p, (size_t)(end - p), "|SIG24"); 258 break; 259 case FPSIG53: 260 /* 53-bit significand, double precision. */ 261 p += mdb_snprintf(p, (size_t)(end - p), "|SIG53"); 262 break; 263 case FPSIG64: 264 /* 64-bit significand, double extended precision. */ 265 p += mdb_snprintf(p, (size_t)(end - p), "|SIG64"); 266 break; 267 default: 268 /* 269 * Should never happen. 270 * Value 0x00000100 is 'Reserved'. 271 */ 272 break; 273 } 274 275 /* 276 * Decode rounding control options. 277 */ 278 switch (cw & FPRC) { 279 case FPRTN: 280 /* Round to nearest, or to even if equidistant. */ 281 p += mdb_snprintf(p, (size_t)(end - p), "|RTN"); 282 break; 283 case FPRD: 284 /* Round down. */ 285 p += mdb_snprintf(p, (size_t)(end - p), "|RD"); 286 break; 287 case FPRU: 288 /* Round up. */ 289 p += mdb_snprintf(p, (size_t)(end - p), "|RU"); 290 break; 291 case FPCHOP: 292 /* Truncate. */ 293 p += mdb_snprintf(p, (size_t)(end - p), "|RTZ"); 294 break; 295 default: 296 /* 297 * This is a two-bit field. 298 * No other options left. 299 */ 300 break; 301 } 302 303 /* 304 * Decode infinity control options. 305 * 306 * This field has been retained for compatibility with 307 * the 287 and earlier co-processors. 308 * In the more modern FPUs, this bit is disregarded and 309 * both -infinity and +infinity are respected. 310 * Comment source: SIMPLY FPU by Raymond Filiatreault 311 */ 312 switch (cw & FPIC) { 313 case FPP: 314 /* 315 * Projective infinity. 316 * Both -infinity and +infinity are treated as 317 * unsigned infinity. 318 */ 319 p += mdb_snprintf(p, (size_t)(end - p), "|P"); 320 break; 321 case FPA: 322 /* 323 * Affine infinity. 324 * Respects both -infinity and +infinity. 325 */ 326 p += mdb_snprintf(p, (size_t)(end - p), "|A"); 327 break; 328 default: 329 /* 330 * This is a one-bit field. 331 * No other options left. 332 */ 333 break; 334 } 335 336 if (cw & WFPB17) 337 p += mdb_snprintf(p, (size_t)(end - p), "|WFPB17"); 338 if (cw & WFPB24) 339 p += mdb_snprintf(p, (size_t)(end - p), "|WFPB24"); 340 341 if (buf[0] == '|') 342 return (buf + 1); 343 344 return ("0"); 345 } 346 347 static const char * 348 fpsw2str(uint32_t cw, char *buf, size_t nbytes) 349 { 350 char *end = buf + nbytes; 351 char *p = buf; 352 353 buf[0] = '\0'; 354 355 /* 356 * Decode all masks in the 80387 status word. 357 */ 358 if (cw & FPS_IE) 359 p += mdb_snprintf(p, (size_t)(end - p), "|IE"); 360 if (cw & FPS_DE) 361 p += mdb_snprintf(p, (size_t)(end - p), "|DE"); 362 if (cw & FPS_ZE) 363 p += mdb_snprintf(p, (size_t)(end - p), "|ZE"); 364 if (cw & FPS_OE) 365 p += mdb_snprintf(p, (size_t)(end - p), "|OE"); 366 if (cw & FPS_UE) 367 p += mdb_snprintf(p, (size_t)(end - p), "|UE"); 368 if (cw & FPS_PE) 369 p += mdb_snprintf(p, (size_t)(end - p), "|PE"); 370 if (cw & FPS_SF) 371 p += mdb_snprintf(p, (size_t)(end - p), "|SF"); 372 if (cw & FPS_ES) 373 p += mdb_snprintf(p, (size_t)(end - p), "|ES"); 374 if (cw & FPS_C0) 375 p += mdb_snprintf(p, (size_t)(end - p), "|C0"); 376 if (cw & FPS_C1) 377 p += mdb_snprintf(p, (size_t)(end - p), "|C1"); 378 if (cw & FPS_C2) 379 p += mdb_snprintf(p, (size_t)(end - p), "|C2"); 380 if (cw & FPS_C3) 381 p += mdb_snprintf(p, (size_t)(end - p), "|C3"); 382 if (cw & FPS_B) 383 p += mdb_snprintf(p, (size_t)(end - p), "|B"); 384 385 if (buf[0] == '|') 386 return (buf + 1); 387 388 return ("0"); 389 } 390 391 static const char * 392 fpmxcsr2str(uint32_t mxcsr, char *buf, size_t nbytes) 393 { 394 char *end = buf + nbytes; 395 char *p = buf; 396 397 buf[0] = '\0'; 398 399 /* 400 * Decode the MXCSR word 401 */ 402 if (mxcsr & SSE_IE) 403 p += mdb_snprintf(p, (size_t)(end - p), "|IE"); 404 if (mxcsr & SSE_DE) 405 p += mdb_snprintf(p, (size_t)(end - p), "|DE"); 406 if (mxcsr & SSE_ZE) 407 p += mdb_snprintf(p, (size_t)(end - p), "|ZE"); 408 if (mxcsr & SSE_OE) 409 p += mdb_snprintf(p, (size_t)(end - p), "|OE"); 410 if (mxcsr & SSE_UE) 411 p += mdb_snprintf(p, (size_t)(end - p), "|UE"); 412 if (mxcsr & SSE_PE) 413 p += mdb_snprintf(p, (size_t)(end - p), "|PE"); 414 415 if (mxcsr & SSE_DAZ) 416 p += mdb_snprintf(p, (size_t)(end - p), "|DAZ"); 417 418 if (mxcsr & SSE_IM) 419 p += mdb_snprintf(p, (size_t)(end - p), "|IM"); 420 if (mxcsr & SSE_DM) 421 p += mdb_snprintf(p, (size_t)(end - p), "|DM"); 422 if (mxcsr & SSE_ZM) 423 p += mdb_snprintf(p, (size_t)(end - p), "|ZM"); 424 if (mxcsr & SSE_OM) 425 p += mdb_snprintf(p, (size_t)(end - p), "|OM"); 426 if (mxcsr & SSE_UM) 427 p += mdb_snprintf(p, (size_t)(end - p), "|UM"); 428 if (mxcsr & SSE_PM) 429 p += mdb_snprintf(p, (size_t)(end - p), "|PM"); 430 431 if ((mxcsr & SSE_RC) == (SSE_RD|SSE_RU)) 432 p += mdb_snprintf(p, (size_t)(end - p), "|RTZ"); 433 else if (mxcsr & SSE_RD) 434 p += mdb_snprintf(p, (size_t)(end - p), "|RD"); 435 else if (mxcsr & SSE_RU) 436 p += mdb_snprintf(p, (size_t)(end - p), "|RU"); 437 else 438 p += mdb_snprintf(p, (size_t)(end - p), "|RTN"); 439 440 if (mxcsr & SSE_FZ) 441 p += mdb_snprintf(p, (size_t)(end - p), "|FZ"); 442 443 if (buf[0] == '|') 444 return (buf + 1); 445 return ("0"); 446 } 447 448 /*ARGSUSED*/ 449 int 450 pt_fpregs(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) 451 { 452 mdb_tgt_t *t = mdb.m_target; 453 mdb_tgt_tid_t tid; 454 uint32_t hw = FP_NO; 455 uint_t sse = 0; 456 prfpregset_t fprs; 457 struct _fpstate fps; 458 char buf[256]; 459 uint_t top; 460 int i; 461 462 /* 463 * Union for overlaying _fpreg structure on to quad-precision 464 * floating-point value (long double). 465 */ 466 union { 467 struct _fpreg reg; 468 long double ld; 469 } fpru; 470 471 /* 472 * Array of strings corresponding to FPU tag word values (see 473 * section 7.3.6 of the Intel Programmer's Reference Manual). 474 */ 475 const char *tag_strings[] = { "valid", "zero", "special", "empty" }; 476 477 if (argc != 0) 478 return (DCMD_USAGE); 479 480 if (t->t_pshandle == NULL || Pstate(t->t_pshandle) == PS_UNDEAD) { 481 mdb_warn("no process active\n"); 482 return (DCMD_ERR); 483 } 484 485 if (Pstate(t->t_pshandle) == PS_LOST) { 486 mdb_warn("debugger has lost control of process\n"); 487 return (DCMD_ERR); 488 } 489 490 if (flags & DCMD_ADDRSPEC) 491 tid = (mdb_tgt_tid_t)addr; 492 else 493 tid = PTL_TID(t); 494 495 if (mdb_tgt_readsym(t, MDB_TGT_AS_VIRT, &hw, 496 sizeof (hw), "libc.so", "_fp_hw") < 0 && 497 mdb_tgt_readsym(t, MDB_TGT_AS_VIRT, &hw, 498 sizeof (hw), MDB_TGT_OBJ_EXEC, "_fp_hw") < 0) 499 mdb_warn("failed to read _fp_hw value"); 500 501 if (mdb_tgt_readsym(t, MDB_TGT_AS_VIRT, &sse, 502 sizeof (sse), "libc.so", "_sse_hw") < 0 && 503 mdb_tgt_readsym(t, MDB_TGT_AS_VIRT, &sse, 504 sizeof (sse), MDB_TGT_OBJ_EXEC, "_sse_hw") < 0) 505 mdb_warn("failed to read _sse_hw value"); 506 507 mdb_printf("_fp_hw 0x%02x (", hw); 508 switch (hw) { 509 case FP_SW: 510 mdb_printf("80387 software emulator"); 511 break; 512 case FP_287: 513 mdb_printf("80287 chip"); 514 break; 515 case FP_387: 516 mdb_printf("80387 chip"); 517 break; 518 case FP_486: 519 mdb_printf("80486 chip"); 520 break; 521 default: 522 mdb_printf("no floating point support"); 523 break; 524 } 525 if (sse) 526 mdb_printf(" with SSE"); 527 mdb_printf(")\n"); 528 529 if (!(hw & FP_HW)) 530 return (DCMD_OK); /* just abort if no hardware present */ 531 532 if (PTL_GETFPREGS(t, tid, &fprs) != 0) { 533 mdb_warn("failed to get floating point registers"); 534 return (DCMD_ERR); 535 } 536 537 bcopy(&fprs.fp_reg_set.fpchip_state, &fps, sizeof (fps)); 538 539 fps.cw &= 0xffff; /* control word is really 16 bits */ 540 fps.sw &= 0xffff; /* status word is really 16 bits */ 541 fps.status &= 0xffff; /* saved status word is really 16 bits */ 542 fps.cssel &= 0xffff; /* %cs is really 16-bits */ 543 fps.datasel &= 0xffff; /* %ds is really 16-bits too */ 544 545 mdb_printf("cw 0x%04x (%s)\n", fps.cw, 546 fpcw2str(fps.cw, buf, sizeof (buf))); 547 548 top = (fps.sw & FPS_TOP) >> 11; 549 mdb_printf("sw 0x%04x (TOP=0t%u) (%s)\n", fps.sw, 550 top, fpsw2str(fps.sw, buf, sizeof (buf))); 551 552 mdb_printf("xcp sw 0x%04x (%s)\n\n", fps.status, 553 fpsw2str(fps.status, buf, sizeof (buf))); 554 555 mdb_printf("ipoff %a\n", fps.ipoff); 556 mdb_printf("cssel 0x%x\n", fps.cssel); 557 mdb_printf("dtoff %a\n", fps.dataoff); 558 mdb_printf("dtsel 0x%x\n\n", fps.datasel); 559 560 for (i = 0; i < 8; i++) { 561 /* 562 * Recall that we need to use the current TOP-of-stack value to 563 * associate the _st[] index back to a physical register number, 564 * since tag word indices are physical register numbers. Then 565 * to get the tag value, we shift over two bits for each tag 566 * index, and then grab the bottom two bits. 567 */ 568 uint_t tag_index = (i + top) & 7; 569 uint_t tag_value = (fps.tag >> (tag_index * 2)) & 3; 570 571 fpru.reg = fps._st[i]; 572 mdb_printf("%%st%d 0x%04x.%04x%04x%04x%04x = %lg %s\n", 573 i, fpru.reg.exponent, 574 fpru.reg.significand[3], fpru.reg.significand[2], 575 fpru.reg.significand[1], fpru.reg.significand[0], 576 fpru.ld, tag_strings[tag_value]); 577 } 578 579 if (!sse) 580 return (DCMD_OK); 581 582 mdb_printf("\nmxcsr 0x%04x (%s)\n", fps.mxcsr, 583 fpmxcsr2str(fps.mxcsr, buf, sizeof (buf))); 584 mdb_printf("xcp 0x%04x (%s)\n\n", fps.xstatus, 585 fpmxcsr2str(fps.xstatus, buf, sizeof (buf))); 586 587 for (i = 0; i < 8; i++) 588 mdb_printf("%%xmm%d 0x%08x%08x%08x%08x\n", i, 589 fps.xmm[i][3], fps.xmm[i][2], 590 fps.xmm[i][1], fps.xmm[i][0]); 591 592 return (DCMD_OK); 593 } 594 595 /*ARGSUSED*/ 596 int 597 pt_getfpreg(mdb_tgt_t *t, mdb_tgt_tid_t tid, ushort_t rd_num, 598 ushort_t rd_flags, mdb_tgt_reg_t *rp) 599 { 600 return (set_errno(ENOTSUP)); 601 } 602 603 /*ARGSUSED*/ 604 int 605 pt_putfpreg(mdb_tgt_t *t, mdb_tgt_tid_t tid, ushort_t rd_num, 606 ushort_t rd_flags, mdb_tgt_reg_t rval) 607 { 608 return (set_errno(ENOTSUP)); 609 } 610 611 /*ARGSUSED*/ 612 void 613 pt_addfpregs(mdb_tgt_t *t) 614 { 615 /* not implemented */ 616 } 617 618 /*ARGSUSED*/ 619 int 620 pt_frameregs(void *arglim, uintptr_t pc, uint_t argc, const long *argv, 621 const mdb_tgt_gregset_t *gregs, boolean_t pc_faked) 622 { 623 return (set_errno(ENOTSUP)); 624 } 625 626 /*ARGSUSED*/ 627 const char * 628 pt_disasm(const GElf_Ehdr *ehp) 629 { 630 return ("ia32"); 631 } 632 633 /* 634 * Determine the return address for the current frame. 635 */ 636 int 637 pt_step_out(mdb_tgt_t *t, uintptr_t *p) 638 { 639 const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 640 641 if (Pstate(t->t_pshandle) != PS_STOP) 642 return (set_errno(EMDB_TGTBUSY)); 643 644 return (mdb_ia32_step_out(t, p, psp->pr_reg[EIP], psp->pr_reg[EBP], 645 psp->pr_reg[UESP], pt_read_instr(t))); 646 } 647 648 /* 649 * Return the address of the next instruction following a call, or return -1 650 * and set errno to EAGAIN if the target should just single-step. 651 */ 652 int 653 pt_next(mdb_tgt_t *t, uintptr_t *p) 654 { 655 const lwpstatus_t *psp = &Pstatus(t->t_pshandle)->pr_lwp; 656 657 if (Pstate(t->t_pshandle) != PS_STOP) 658 return (set_errno(EMDB_TGTBUSY)); 659 660 return (mdb_ia32_next(t, p, psp->pr_reg[EIP], pt_read_instr(t))); 661 } 662