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