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